Skip to content

Commit 0afb868

Browse files
committed
Merge branch 'suirad-windows-wide-imports'
2 parents e98ba5f + fff6e47 commit 0afb868

File tree

3 files changed

+63
-23
lines changed

3 files changed

+63
-23
lines changed

std/buf_map.zig

Lines changed: 27 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ pub const BufMap = struct {
1616
return self;
1717
}
1818

19-
pub fn deinit(self: *const BufMap) void {
19+
pub fn deinit(self: *BufMap) void {
2020
var it = self.hash_map.iterator();
2121
while (true) {
2222
const entry = it.next() orelse break;
@@ -27,16 +27,34 @@ pub const BufMap = struct {
2727
self.hash_map.deinit();
2828
}
2929

30+
/// Same as `set` but the key and value become owned by the BufMap rather
31+
/// than being copied.
32+
/// If `setMove` fails, the ownership of key and value does not transfer.
33+
pub fn setMove(self: *BufMap, key: []u8, value: []u8) !void {
34+
const get_or_put = try self.hash_map.getOrPut(key);
35+
if (get_or_put.found_existing) {
36+
self.free(get_or_put.kv.key);
37+
get_or_put.kv.key = key;
38+
}
39+
get_or_put.kv.value = value;
40+
}
41+
42+
/// `key` and `value` are copied into the BufMap.
3043
pub fn set(self: *BufMap, key: []const u8, value: []const u8) !void {
31-
self.delete(key);
32-
const key_copy = try self.copy(key);
33-
errdefer self.free(key_copy);
3444
const value_copy = try self.copy(value);
3545
errdefer self.free(value_copy);
36-
_ = try self.hash_map.put(key_copy, value_copy);
46+
// Avoid copying key if it already exists
47+
const get_or_put = try self.hash_map.getOrPut(key);
48+
if (!get_or_put.found_existing) {
49+
get_or_put.kv.key = self.copy(key) catch |err| {
50+
_ = self.hash_map.remove(key);
51+
return err;
52+
};
53+
}
54+
get_or_put.kv.value = value_copy;
3755
}
3856

39-
pub fn get(self: *const BufMap, key: []const u8) ?[]const u8 {
57+
pub fn get(self: BufMap, key: []const u8) ?[]const u8 {
4058
const entry = self.hash_map.get(key) orelse return null;
4159
return entry.value;
4260
}
@@ -47,19 +65,19 @@ pub const BufMap = struct {
4765
self.free(entry.value);
4866
}
4967

50-
pub fn count(self: *const BufMap) usize {
68+
pub fn count(self: BufMap) usize {
5169
return self.hash_map.count();
5270
}
5371

5472
pub fn iterator(self: *const BufMap) BufMapHashMap.Iterator {
5573
return self.hash_map.iterator();
5674
}
5775

58-
fn free(self: *const BufMap, value: []const u8) void {
76+
fn free(self: BufMap, value: []const u8) void {
5977
self.hash_map.allocator.free(value);
6078
}
6179

62-
fn copy(self: *const BufMap, value: []const u8) ![]const u8 {
80+
fn copy(self: BufMap, value: []const u8) ![]u8 {
6381
return mem.dupe(self.hash_map.allocator, u8, value);
6482
}
6583
};

std/os/index.zig

Lines changed: 33 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -702,8 +702,8 @@ pub fn getEnvMap(allocator: *Allocator) !BufMap {
702702
errdefer result.deinit();
703703

704704
if (is_windows) {
705-
const ptr = windows.GetEnvironmentStringsA() orelse return error.OutOfMemory;
706-
defer assert(windows.FreeEnvironmentStringsA(ptr) != 0);
705+
const ptr = windows.GetEnvironmentStringsW() orelse return error.OutOfMemory;
706+
defer assert(windows.FreeEnvironmentStringsW(ptr) != 0);
707707

708708
var i: usize = 0;
709709
while (true) {
@@ -712,17 +712,21 @@ pub fn getEnvMap(allocator: *Allocator) !BufMap {
712712
const key_start = i;
713713

714714
while (ptr[i] != 0 and ptr[i] != '=') : (i += 1) {}
715-
const key = ptr[key_start..i];
715+
const key_w = ptr[key_start..i];
716+
const key = try std.unicode.utf16leToUtf8Alloc(allocator, key_w);
717+
errdefer allocator.free(key);
716718

717719
if (ptr[i] == '=') i += 1;
718720

719721
const value_start = i;
720722
while (ptr[i] != 0) : (i += 1) {}
721-
const value = ptr[value_start..i];
723+
const value_w = ptr[value_start..i];
724+
const value = try std.unicode.utf16leToUtf8Alloc(allocator, value_w);
725+
errdefer allocator.free(value);
722726

723727
i += 1; // skip over null byte
724728

725-
try result.set(key, value);
729+
try result.setMove(key, value);
726730
}
727731
} else {
728732
for (posix_environ_raw) |ptr| {
@@ -740,6 +744,11 @@ pub fn getEnvMap(allocator: *Allocator) !BufMap {
740744
}
741745
}
742746

747+
test "os.getEnvMap" {
748+
var env = try getEnvMap(std.debug.global_allocator);
749+
defer env.deinit();
750+
}
751+
743752
/// TODO make this go through libc when we have it
744753
pub fn getEnvPosix(key: []const u8) ?[]const u8 {
745754
for (posix_environ_raw) |ptr| {
@@ -760,21 +769,24 @@ pub fn getEnvPosix(key: []const u8) ?[]const u8 {
760769
pub const GetEnvVarOwnedError = error{
761770
OutOfMemory,
762771
EnvironmentVariableNotFound,
772+
773+
/// See https://github.com/ziglang/zig/issues/1774
774+
InvalidUtf8,
763775
};
764776

765777
/// Caller must free returned memory.
766778
/// TODO make this go through libc when we have it
767779
pub fn getEnvVarOwned(allocator: *mem.Allocator, key: []const u8) GetEnvVarOwnedError![]u8 {
768780
if (is_windows) {
769-
const key_with_null = try cstr.addNullByte(allocator, key);
781+
const key_with_null = try std.unicode.utf8ToUtf16LeWithNull(allocator, key);
770782
defer allocator.free(key_with_null);
771783

772-
var buf = try allocator.alloc(u8, 256);
773-
errdefer allocator.free(buf);
784+
var buf = try allocator.alloc(u16, 256);
785+
defer allocator.free(buf);
774786

775787
while (true) {
776788
const windows_buf_len = math.cast(windows.DWORD, buf.len) catch return error.OutOfMemory;
777-
const result = windows.GetEnvironmentVariableA(key_with_null.ptr, buf.ptr, windows_buf_len);
789+
const result = windows.GetEnvironmentVariableW(key_with_null.ptr, buf.ptr, windows_buf_len);
778790

779791
if (result == 0) {
780792
const err = windows.GetLastError();
@@ -788,18 +800,28 @@ pub fn getEnvVarOwned(allocator: *mem.Allocator, key: []const u8) GetEnvVarOwned
788800
}
789801

790802
if (result > buf.len) {
791-
buf = try allocator.realloc(u8, buf, result);
803+
buf = try allocator.realloc(u16, buf, result);
792804
continue;
793805
}
794806

795-
return allocator.shrink(u8, buf, result);
807+
return std.unicode.utf16leToUtf8Alloc(allocator, buf) catch |err| switch (err) {
808+
error.DanglingSurrogateHalf => return error.InvalidUtf8,
809+
error.ExpectedSecondSurrogateHalf => return error.InvalidUtf8,
810+
error.UnexpectedSecondSurrogateHalf => return error.InvalidUtf8,
811+
error.OutOfMemory => return error.OutOfMemory,
812+
};
796813
}
797814
} else {
798815
const result = getEnvPosix(key) orelse return error.EnvironmentVariableNotFound;
799816
return mem.dupe(allocator, u8, result);
800817
}
801818
}
802819

820+
test "os.getEnvVarOwned" {
821+
var ga = debug.global_allocator;
822+
debug.assertError(getEnvVarOwned(ga, "BADENV"), error.EnvironmentVariableNotFound);
823+
}
824+
803825
/// Caller must free the returned memory.
804826
pub fn getCwdAlloc(allocator: *Allocator) ![]u8 {
805827
var buf: [MAX_PATH_BYTES]u8 = undefined;

std/os/windows/kernel32.zig

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ pub extern "kernel32" stdcallcc fn FindFirstFileW(lpFileName: [*]const u16, lpFi
5050
pub extern "kernel32" stdcallcc fn FindClose(hFindFile: HANDLE) BOOL;
5151
pub extern "kernel32" stdcallcc fn FindNextFileW(hFindFile: HANDLE, lpFindFileData: *WIN32_FIND_DATAW) BOOL;
5252

53-
pub extern "kernel32" stdcallcc fn FreeEnvironmentStringsA(penv: [*]u8) BOOL;
53+
pub extern "kernel32" stdcallcc fn FreeEnvironmentStringsW(penv: [*]u16) BOOL;
5454

5555
pub extern "kernel32" stdcallcc fn GetCommandLineA() LPSTR;
5656

@@ -63,9 +63,9 @@ pub extern "kernel32" stdcallcc fn GetCurrentDirectoryW(nBufferLength: DWORD, lp
6363
pub extern "kernel32" stdcallcc fn GetCurrentThread() HANDLE;
6464
pub extern "kernel32" stdcallcc fn GetCurrentThreadId() DWORD;
6565

66-
pub extern "kernel32" stdcallcc fn GetEnvironmentStringsA() ?[*]u8;
66+
pub extern "kernel32" stdcallcc fn GetEnvironmentStringsW() ?[*]u16;
6767

68-
pub extern "kernel32" stdcallcc fn GetEnvironmentVariableA(lpName: LPCSTR, lpBuffer: LPSTR, nSize: DWORD) DWORD;
68+
pub extern "kernel32" stdcallcc fn GetEnvironmentVariableW(lpName: LPWSTR, lpBuffer: LPWSTR, nSize: DWORD) DWORD;
6969

7070
pub extern "kernel32" stdcallcc fn GetExitCodeProcess(hProcess: HANDLE, lpExitCode: *DWORD) BOOL;
7171

0 commit comments

Comments
 (0)