Commit 5dfca87a65

Suirad <suirad@users.noreply.github.com>
2018-11-22 11:15:22
Update windows imports
1 parent 823969a
Changed files (2)
std
std/os/windows/kernel32.zig
@@ -50,7 +50,7 @@ pub extern "kernel32" stdcallcc fn FindFirstFileW(lpFileName: [*]const u16, lpFi
 pub extern "kernel32" stdcallcc fn FindClose(hFindFile: HANDLE) BOOL;
 pub extern "kernel32" stdcallcc fn FindNextFileW(hFindFile: HANDLE, lpFindFileData: *WIN32_FIND_DATAW) BOOL;
 
-pub extern "kernel32" stdcallcc fn FreeEnvironmentStringsA(penv: [*]u8) BOOL;
+pub extern "kernel32" stdcallcc fn FreeEnvironmentStringsW(penv: [*]u16) BOOL;
 
 pub extern "kernel32" stdcallcc fn GetCommandLineA() LPSTR;
 
@@ -63,9 +63,9 @@ pub extern "kernel32" stdcallcc fn GetCurrentDirectoryW(nBufferLength: DWORD, lp
 pub extern "kernel32" stdcallcc fn GetCurrentThread() HANDLE;
 pub extern "kernel32" stdcallcc fn GetCurrentThreadId() DWORD;
 
-pub extern "kernel32" stdcallcc fn GetEnvironmentStringsA() ?[*]u8;
+pub extern "kernel32" stdcallcc fn GetEnvironmentStringsW() ?[*]u16;
 
-pub extern "kernel32" stdcallcc fn GetEnvironmentVariableA(lpName: LPCSTR, lpBuffer: LPSTR, nSize: DWORD) DWORD;
+pub extern "kernel32" stdcallcc fn GetEnvironmentVariableW(lpName: LPWSTR, lpBuffer: LPWSTR, nSize: DWORD) DWORD;
 
 pub extern "kernel32" stdcallcc fn GetExitCodeProcess(hProcess: HANDLE, lpExitCode: *DWORD) BOOL;
 
std/os/index.zig
@@ -702,8 +702,8 @@ pub fn getEnvMap(allocator: *Allocator) !BufMap {
     errdefer result.deinit();
 
     if (is_windows) {
-        const ptr = windows.GetEnvironmentStringsA() orelse return error.OutOfMemory;
-        defer assert(windows.FreeEnvironmentStringsA(ptr) != 0);
+        const ptr = windows.GetEnvironmentStringsW() orelse return error.OutOfMemory;
+        defer assert(windows.FreeEnvironmentStringsW(ptr) != 0);
 
         var i: usize = 0;
         while (true) {
@@ -712,17 +712,50 @@ pub fn getEnvMap(allocator: *Allocator) !BufMap {
             const key_start = i;
 
             while (ptr[i] != 0 and ptr[i] != '=') : (i += 1) {}
-            const key = ptr[key_start..i];
+            
+            const stack_var_len = 50;
+            const key_slice = ptr[key_start..i];
+            var key: []u8 = undefined;
+            var heap_key = false;
+
+            // parse the key on the stack if smaller than 'stack_var_len'
+            if (key_slice.len < stack_var_len-@sizeOf(usize)) {
+                var buf = []u8{0} ** stack_var_len;
+                var fallocator = &std.heap.FixedBufferAllocator.init(buf[0..]).allocator;
+                key = try std.unicode.utf16leToUtf8Alloc(fallocator, key_slice);
+            } else {
+                key = try std.unicode.utf16leToUtf8Alloc(allocator, key_slice);
+                heap_key = true; // key needs to outlive this scope, so we cannot defer
+            }
 
             if (ptr[i] == '=') i += 1;
 
             const value_start = i;
             while (ptr[i] != 0) : (i += 1) {}
-            const value = ptr[value_start..i];
+
+            const value_slice = ptr[value_start..i];
+            var value: []u8 = undefined;
+            var heap_value = false;
+
+            if (value_slice.len < stack_var_len-@sizeOf(usize)) {
+                var buf = []u8{0} ** stack_var_len;
+                var fallocator = &std.heap.FixedBufferAllocator.init(buf[0..]).allocator;
+                value = try std.unicode.utf16leToUtf8Alloc(fallocator, value_slice);
+            } else {
+                value = try std.unicode.utf16leToUtf8Alloc(allocator, value_slice);
+                heap_value = true; // value needs to outlive this scope, so we cannot defer
+            }
 
             i += 1; // skip over null byte
 
             try result.set(key, value);
+
+            if (heap_key) {
+                allocator.free(key);
+            }
+            if (heap_value) {
+                allocator.free(value);
+            }
         }
     } else {
         for (posix_environ_raw) |ptr| {
@@ -740,6 +773,19 @@ pub fn getEnvMap(allocator: *Allocator) !BufMap {
     }
 }
 
+test "os.getEnvMap" {
+    var env = try getEnvMap(std.debug.global_allocator);
+    var seen_path = false;
+    var it = env.iterator();
+    while (it.next()) |pair| {
+       if (mem.eql(u8, pair.key, "PATH")) {
+            seen_path = true;
+       }
+    }
+
+    assert(seen_path == true);
+}
+
 /// TODO make this go through libc when we have it
 pub fn getEnvPosix(key: []const u8) ?[]const u8 {
     for (posix_environ_raw) |ptr| {
@@ -760,21 +806,27 @@ pub fn getEnvPosix(key: []const u8) ?[]const u8 {
 pub const GetEnvVarOwnedError = error{
     OutOfMemory,
     EnvironmentVariableNotFound,
+    DanglingSurrogateHalf,
+    ExpectedSecondSurrogateHalf,
+    UnexpectedSecondSurrogateHalf,
+
+    /// See https://github.com/ziglang/zig/issues/1774
+    InvalidUtf8,
 };
 
 /// Caller must free returned memory.
 /// TODO make this go through libc when we have it
 pub fn getEnvVarOwned(allocator: *mem.Allocator, key: []const u8) GetEnvVarOwnedError![]u8 {
     if (is_windows) {
-        const key_with_null = try cstr.addNullByte(allocator, key);
+        const key_with_null = try std.unicode.utf8ToUtf16LeWithNull(allocator, key);
         defer allocator.free(key_with_null);
 
-        var buf = try allocator.alloc(u8, 256);
-        errdefer allocator.free(buf);
+        var buf = try allocator.alloc(u16, 256);
+        defer allocator.free(buf);
 
         while (true) {
             const windows_buf_len = math.cast(windows.DWORD, buf.len) catch return error.OutOfMemory;
-            const result = windows.GetEnvironmentVariableA(key_with_null.ptr, buf.ptr, windows_buf_len);
+            const result = windows.GetEnvironmentVariableW(key_with_null.ptr, buf.ptr, windows_buf_len);
 
             if (result == 0) {
                 const err = windows.GetLastError();
@@ -788,11 +840,11 @@ pub fn getEnvVarOwned(allocator: *mem.Allocator, key: []const u8) GetEnvVarOwned
             }
 
             if (result > buf.len) {
-                buf = try allocator.realloc(u8, buf, result);
+                buf = try allocator.realloc(u16, buf, result);
                 continue;
             }
 
-            return allocator.shrink(u8, buf, result);
+            return try std.unicode.utf16leToUtf8Alloc(allocator, buf);
         }
     } else {
         const result = getEnvPosix(key) orelse return error.EnvironmentVariableNotFound;
@@ -800,6 +852,15 @@ pub fn getEnvVarOwned(allocator: *mem.Allocator, key: []const u8) GetEnvVarOwned
     }
 }
 
+test "os.getEnvVarOwned" {
+    switch (builtin.os) {
+        builtin.Os.windows, builtin.Os.linux, builtin.Os.macosx,
+            builtin.Os.ios => _ = try getEnvVarOwned(debug.global_allocator, "PATH"),
+        else => @compileError("unimplemented"),
+    }
+}
+
+
 /// Caller must free the returned memory.
 pub fn getCwdAlloc(allocator: *Allocator) ![]u8 {
     var buf: [MAX_PATH_BYTES]u8 = undefined;