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 {...@@ -308,7 +308,7 @@ pub const Builder = struct {
308 }308 }
309309
310 fn processNixOSEnvVars(self: &Builder) {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 var it = mem.split(nix_cflags_compile, " ");312 var it = mem.split(nix_cflags_compile, " ");
313 while (true) {313 while (true) {
314 const word = it.next() ?? break;314 const word = it.next() ?? break;
...@@ -323,8 +323,10 @@ pub const Builder = struct {...@@ -323,8 +323,10 @@ pub const Builder = struct {
323 break;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 var it = mem.split(nix_ldflags, " ");330 var it = mem.split(nix_ldflags, " ");
329 while (true) {331 while (true) {
330 const word = it.next() ?? break;332 const word = it.next() ?? break;
...@@ -342,6 +344,8 @@ pub const Builder = struct {...@@ -342,6 +344,8 @@ pub const Builder = struct {
342 break;344 break;
343 }345 }
344 }346 }
347 } else |err| {
348 assert(err == error.EnvironmentVariableNotFound);
345 }349 }
346 }350 }
347351
...@@ -1248,7 +1252,13 @@ pub const LibExeObjStep = struct {...@@ -1248,7 +1252,13 @@ pub const LibExeObjStep = struct {
1248 }1252 }
12491253
1250 fn makeC(self: &LibExeObjStep) -> %void {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 const builder = self.builder;1262 const builder = self.builder;
12531263
1254 assert(!self.is_zig);1264 assert(!self.is_zig);
std/os/child_process.zig+2-1
...@@ -564,7 +564,7 @@ pub const ChildProcess = struct {...@@ -564,7 +564,7 @@ pub const ChildProcess = struct {
564 const cwd_ptr = if (cwd_slice) |cwd| cwd.ptr else null;564 const cwd_ptr = if (cwd_slice) |cwd| cwd.ptr else null;
565565
566 const maybe_envp_buf = if (self.env_map) |env_map| {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 } else {568 } else {
569 null569 null
570 };570 };
...@@ -578,6 +578,7 @@ pub const ChildProcess = struct {...@@ -578,6 +578,7 @@ pub const ChildProcess = struct {
578 const err = windows.GetLastError();578 const err = windows.GetLastError();
579 return switch (err) {579 return switch (err) {
580 windows.ERROR.FILE_NOT_FOUND => error.FileNotFound,580 windows.ERROR.FILE_NOT_FOUND => error.FileNotFound,
581 windows.ERROR.INVALID_PARAMETER => unreachable,
581 else => error.Unexpected,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,6 +32,7 @@ pub const windowsWrite = windows_util.windowsWrite;
32pub const windowsIsTty = windows_util.windowsIsTty;32pub const windowsIsTty = windows_util.windowsIsTty;
33pub const windowsIsCygwinPty = windows_util.windowsIsCygwinPty;33pub const windowsIsCygwinPty = windows_util.windowsIsCygwinPty;
34pub const windowsOpen = windows_util.windowsOpen;34pub const windowsOpen = windows_util.windowsOpen;
35pub const createWindowsEnvBlock = windows_util.createWindowsEnvBlock;
3536
36const debug = @import("../debug.zig");37const debug = @import("../debug.zig");
37const assert = debug.assert;38const assert = debug.assert;
...@@ -48,6 +49,7 @@ const io = @import("../io.zig");...@@ -48,6 +49,7 @@ const io = @import("../io.zig");
48const base64 = @import("../base64.zig");49const base64 = @import("../base64.zig");
49const ArrayList = @import("../array_list.zig").ArrayList;50const ArrayList = @import("../array_list.zig").ArrayList;
50const Buffer = @import("../buffer.zig").Buffer;51const Buffer = @import("../buffer.zig").Buffer;
52const math = @import("../index.zig").math;
5153
52error Unexpected;54error Unexpected;
53error SystemResources;55error SystemResources;
...@@ -362,7 +364,7 @@ pub fn posixExecve(argv: []const []const u8, env_map: &const BufMap,...@@ -362,7 +364,7 @@ pub fn posixExecve(argv: []const []const u8, env_map: &const BufMap,
362 return posixExecveErrnoToErr(posix.getErrno(posix.execve(??argv_buf[0], argv_buf.ptr, envp_buf.ptr)));364 return posixExecveErrnoToErr(posix.getErrno(posix.execve(??argv_buf[0], argv_buf.ptr, envp_buf.ptr)));
363 }365 }
364366
365 const PATH = getEnv("PATH") ?? "/usr/local/bin:/bin/:/usr/bin";367 const PATH = getEnvPosix("PATH") ?? "/usr/local/bin:/bin/:/usr/bin";
366 // PATH.len because it is >= the largest search_path368 // PATH.len because it is >= the largest search_path
367 // +1 for the / to join the search path and exe_path369 // +1 for the / to join the search path and exe_path
368 // +1 for the null terminating byte370 // +1 for the null terminating byte
...@@ -406,29 +408,55 @@ fn posixExecveErrnoToErr(err: usize) -> error {...@@ -406,29 +408,55 @@ fn posixExecveErrnoToErr(err: usize) -> error {
406 };408 };
407}409}
408410
409pub var environ_raw: []&u8 = undefined;411pub var posix_environ_raw: []&u8 = undefined;
410412
411/// Caller must free result when done.413/// Caller must free result when done.
412pub fn getEnvMap(allocator: &Allocator) -> %BufMap {414pub fn getEnvMap(allocator: &Allocator) -> %BufMap {
413 var result = BufMap.init(allocator);415 var result = BufMap.init(allocator);
414 %defer result.deinit();416 %defer result.deinit();
415417
416 for (environ_raw) |ptr| {418 if (is_windows) {
417 var line_i: usize = 0;419 const ptr = windows.GetEnvironmentStringsA() ?? return error.OutOfMemory;
418 while (ptr[line_i] != 0 and ptr[line_i] != '=') : (line_i += 1) {}420 defer assert(windows.FreeEnvironmentStringsA(ptr));
419 const key = ptr[0..line_i];
420421
421 var end_i: usize = line_i;422 var i: usize = 0;
422 while (ptr[end_i] != 0) : (end_i += 1) {}423 while (true) {
423 const value = ptr[line_i + 1..end_i];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;
426 }455 }
427 return result;
428}456}
429457
430pub fn getEnv(key: []const u8) -> ?[]const u8 {458pub fn getEnvPosix(key: []const u8) -> ?[]const u8 {
431 for (environ_raw) |ptr| {459 for (posix_environ_raw) |ptr| {
432 var line_i: usize = 0;460 var line_i: usize = 0;
433 while (ptr[line_i] != 0 and ptr[line_i] != '=') : (line_i += 1) {}461 while (ptr[line_i] != 0 and ptr[line_i] != '=') : (line_i += 1) {}
434 const this_key = ptr[0..line_i];462 const this_key = ptr[0..line_i];
...@@ -444,6 +472,42 @@ pub fn getEnv(key: []const u8) -> ?[]const u8 {...@@ -444,6 +472,42 @@ pub fn getEnv(key: []const u8) -> ?[]const u8 {
444 return null;472 return null;
445}473}
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
447/// Caller must free the returned memory.511/// Caller must free the returned memory.
448pub fn getCwd(allocator: &Allocator) -> %[]u8 {512pub fn getCwd(allocator: &Allocator) -> %[]u8 {
449 switch (builtin.os) {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,12 +32,18 @@ pub extern "kernel32" stdcallcc fn DeleteFileA(lpFileName: LPCSTR) -> bool;
3232
33pub extern "kernel32" stdcallcc fn ExitProcess(exit_code: UINT) -> noreturn;33pub extern "kernel32" stdcallcc fn ExitProcess(exit_code: UINT) -> noreturn;
3434
35pub extern "kernel32" stdcallcc fn FreeEnvironmentStringsA(penv: LPCH) -> BOOL;
36
35pub extern "kernel32" stdcallcc fn GetCommandLineA() -> LPSTR;37pub extern "kernel32" stdcallcc fn GetCommandLineA() -> LPSTR;
3638
37pub extern "kernel32" stdcallcc fn GetConsoleMode(in_hConsoleHandle: HANDLE, out_lpMode: &DWORD) -> bool;39pub extern "kernel32" stdcallcc fn GetConsoleMode(in_hConsoleHandle: HANDLE, out_lpMode: &DWORD) -> bool;
3840
39pub extern "kernel32" stdcallcc fn GetCurrentDirectoryA(nBufferLength: WORD, lpBuffer: ?LPSTR) -> DWORD;41pub 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
41pub extern "kernel32" stdcallcc fn GetExitCodeProcess(hProcess: HANDLE, lpExitCode: &DWORD) -> BOOL;47pub extern "kernel32" stdcallcc fn GetExitCodeProcess(hProcess: HANDLE, lpExitCode: &DWORD) -> BOOL;
4248
43pub extern "kernel32" stdcallcc fn GetLastError() -> DWORD;49pub extern "kernel32" stdcallcc fn GetLastError() -> DWORD;
...@@ -49,11 +55,11 @@ pub extern "kernel32" stdcallcc fn GetFileInformationByHandleEx(in_hFile: HANDLE...@@ -49,11 +55,11 @@ pub extern "kernel32" stdcallcc fn GetFileInformationByHandleEx(in_hFile: HANDLE
49pub extern "kernel32" stdcallcc fn GetFinalPathNameByHandleA(hFile: HANDLE, lpszFilePath: LPSTR,55pub extern "kernel32" stdcallcc fn GetFinalPathNameByHandleA(hFile: HANDLE, lpszFilePath: LPSTR,
50 cchFilePath: DWORD, dwFlags: DWORD) -> DWORD;56 cchFilePath: DWORD, dwFlags: DWORD) -> DWORD;
5157
52pub extern "kernel32" stdcallcc fn GetProcessHeap() -> HANDLE;58pub extern "kernel32" stdcallcc fn GetProcessHeap() -> ?HANDLE;
5359
54pub extern "kernel32" stdcallcc fn GetStdHandle(in_nStdHandle: DWORD) -> ?HANDLE;60pub 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
58pub extern "kernel32" stdcallcc fn HeapFree(hHeap: HANDLE, dwFlags: DWORD, lpMem: LPVOID) -> BOOL;64pub extern "kernel32" stdcallcc fn HeapFree(hHeap: HANDLE, dwFlags: DWORD, lpMem: LPVOID) -> BOOL;
5965
...@@ -91,6 +97,7 @@ pub const HCRYPTPROV = ULONG_PTR;...@@ -91,6 +97,7 @@ pub const HCRYPTPROV = ULONG_PTR;
91pub const HINSTANCE = &@OpaqueType();97pub const HINSTANCE = &@OpaqueType();
92pub const INT = c_int;98pub const INT = c_int;
93pub const LPBYTE = &BYTE;99pub const LPBYTE = &BYTE;
100pub const LPCH = &CHAR;
94pub const LPCSTR = &const CHAR;101pub const LPCSTR = &const CHAR;
95pub const LPCTSTR = &const TCHAR;102pub const LPCTSTR = &const TCHAR;
96pub const LPCVOID = &const c_void;103pub const LPCVOID = &const c_void;
std/os/windows/util.zig+33
...@@ -3,6 +3,7 @@ const os = std.os;...@@ -3,6 +3,7 @@ const os = std.os;
3const windows = std.os.windows;3const windows = std.os.windows;
4const assert = std.debug.assert;4const assert = std.debug.assert;
5const mem = std.mem;5const mem = std.mem;
6const BufMap = std.BufMap;
67
7error WaitAbandoned;8error WaitAbandoned;
8error WaitTimeOut;9error WaitTimeOut;
...@@ -111,3 +112,35 @@ pub fn windowsOpen(file_path: []const u8, desired_access: windows.DWORD, share_m...@@ -111,3 +112,35 @@ pub fn windowsOpen(file_path: []const u8, desired_access: windows.DWORD, share_m
111112
112 return result;113 return result;
113}114}
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 {...@@ -56,7 +56,7 @@ fn callMain(argc: usize, argv: &&u8, envp: &?&u8) -> %void {
5656
57 var env_count: usize = 0;57 var env_count: usize = 0;
58 while (envp[env_count] != null) : (env_count += 1) {}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];
6060
61 std.debug.user_main_fn = root.main;61 std.debug.user_main_fn = root.main;
6262