| author | |
| committer | |
| log | 0afb86868423b454708608f9faa9bf27ce3233f3 |
| tree | 84c5b8ce41886b3740970e76506050c82a718183 |
| parent | e98ba5fc4044cd84ab88b10cb8c88d765884462f |
| parent | fff6e471259071d9ad8466bcdb0ce42c9d7a90d4 |
| signature |
3 files changed, 63 insertions(+), 23 deletions(-)
std/buf_map.zig+27-9| ... | ... | @@ -16,7 +16,7 @@ pub const BufMap = struct { |
| 16 | 16 | return self; |
| 17 | 17 | } |
| 18 | 18 | |
| 19 | pub fn deinit(self: *const BufMap) void { | |
| 19 | pub fn deinit(self: *BufMap) void { | |
| 20 | 20 | var it = self.hash_map.iterator(); |
| 21 | 21 | while (true) { |
| 22 | 22 | const entry = it.next() orelse break; |
| ... | ... | @@ -27,16 +27,34 @@ pub const BufMap = struct { |
| 27 | 27 | self.hash_map.deinit(); |
| 28 | 28 | } |
| 29 | 29 | |
| 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. | |
| 30 | 43 | 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); | |
| 34 | 44 | const value_copy = try self.copy(value); |
| 35 | 45 | 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; | |
| 37 | 55 | } |
| 38 | 56 | |
| 39 | pub fn get(self: *const BufMap, key: []const u8) ?[]const u8 { | |
| 57 | pub fn get(self: BufMap, key: []const u8) ?[]const u8 { | |
| 40 | 58 | const entry = self.hash_map.get(key) orelse return null; |
| 41 | 59 | return entry.value; |
| 42 | 60 | } |
| ... | ... | @@ -47,7 +65,7 @@ pub const BufMap = struct { |
| 47 | 65 | self.free(entry.value); |
| 48 | 66 | } |
| 49 | 67 | |
| 50 | pub fn count(self: *const BufMap) usize { | |
| 68 | pub fn count(self: BufMap) usize { | |
| 51 | 69 | return self.hash_map.count(); |
| 52 | 70 | } |
| 53 | 71 | |
| ... | ... | @@ -55,11 +73,11 @@ pub const BufMap = struct { |
| 55 | 73 | return self.hash_map.iterator(); |
| 56 | 74 | } |
| 57 | 75 | |
| 58 | fn free(self: *const BufMap, value: []const u8) void { | |
| 76 | fn free(self: BufMap, value: []const u8) void { | |
| 59 | 77 | self.hash_map.allocator.free(value); |
| 60 | 78 | } |
| 61 | 79 | |
| 62 | fn copy(self: *const BufMap, value: []const u8) ![]const u8 { | |
| 80 | fn copy(self: BufMap, value: []const u8) ![]u8 { | |
| 63 | 81 | return mem.dupe(self.hash_map.allocator, u8, value); |
| 64 | 82 | } |
| 65 | 83 | }; |
std/os/index.zig+33-11| ... | ... | @@ -702,8 +702,8 @@ pub fn getEnvMap(allocator: *Allocator) !BufMap { |
| 702 | 702 | errdefer result.deinit(); |
| 703 | 703 | |
| 704 | 704 | 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); | |
| 707 | 707 | |
| 708 | 708 | var i: usize = 0; |
| 709 | 709 | while (true) { |
| ... | ... | @@ -712,17 +712,21 @@ pub fn getEnvMap(allocator: *Allocator) !BufMap { |
| 712 | 712 | const key_start = i; |
| 713 | 713 | |
| 714 | 714 | 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); | |
| 716 | 718 | |
| 717 | 719 | if (ptr[i] == '=') i += 1; |
| 718 | 720 | |
| 719 | 721 | const value_start = i; |
| 720 | 722 | 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); | |
| 722 | 726 | |
| 723 | 727 | i += 1; // skip over null byte |
| 724 | 728 | |
| 725 | try result.set(key, value); | |
| 729 | try result.setMove(key, value); | |
| 726 | 730 | } |
| 727 | 731 | } else { |
| 728 | 732 | for (posix_environ_raw) |ptr| { |
| ... | ... | @@ -740,6 +744,11 @@ pub fn getEnvMap(allocator: *Allocator) !BufMap { |
| 740 | 744 | } |
| 741 | 745 | } |
| 742 | 746 | |
| 747 | test "os.getEnvMap" { | |
| 748 | var env = try getEnvMap(std.debug.global_allocator); | |
| 749 | defer env.deinit(); | |
| 750 | } | |
| 751 | ||
| 743 | 752 | /// TODO make this go through libc when we have it |
| 744 | 753 | pub fn getEnvPosix(key: []const u8) ?[]const u8 { |
| 745 | 754 | for (posix_environ_raw) |ptr| { |
| ... | ... | @@ -760,21 +769,24 @@ pub fn getEnvPosix(key: []const u8) ?[]const u8 { |
| 760 | 769 | pub const GetEnvVarOwnedError = error{ |
| 761 | 770 | OutOfMemory, |
| 762 | 771 | EnvironmentVariableNotFound, |
| 772 | ||
| 773 | /// See https://github.com/ziglang/zig/issues/1774 | |
| 774 | InvalidUtf8, | |
| 763 | 775 | }; |
| 764 | 776 | |
| 765 | 777 | /// Caller must free returned memory. |
| 766 | 778 | /// TODO make this go through libc when we have it |
| 767 | 779 | pub fn getEnvVarOwned(allocator: *mem.Allocator, key: []const u8) GetEnvVarOwnedError![]u8 { |
| 768 | 780 | if (is_windows) { |
| 769 | const key_with_null = try cstr.addNullByte(allocator, key); | |
| 781 | const key_with_null = try std.unicode.utf8ToUtf16LeWithNull(allocator, key); | |
| 770 | 782 | defer allocator.free(key_with_null); |
| 771 | 783 | |
| 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); | |
| 774 | 786 | |
| 775 | 787 | while (true) { |
| 776 | 788 | 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); | |
| 778 | 790 | |
| 779 | 791 | if (result == 0) { |
| 780 | 792 | const err = windows.GetLastError(); |
| ... | ... | @@ -788,11 +800,16 @@ pub fn getEnvVarOwned(allocator: *mem.Allocator, key: []const u8) GetEnvVarOwned |
| 788 | 800 | } |
| 789 | 801 | |
| 790 | 802 | if (result > buf.len) { |
| 791 | buf = try allocator.realloc(u8, buf, result); | |
| 803 | buf = try allocator.realloc(u16, buf, result); | |
| 792 | 804 | continue; |
| 793 | 805 | } |
| 794 | 806 | |
| 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 | }; | |
| 796 | 813 | } |
| 797 | 814 | } else { |
| 798 | 815 | const result = getEnvPosix(key) orelse return error.EnvironmentVariableNotFound; |
| ... | ... | @@ -800,6 +817,11 @@ pub fn getEnvVarOwned(allocator: *mem.Allocator, key: []const u8) GetEnvVarOwned |
| 800 | 817 | } |
| 801 | 818 | } |
| 802 | 819 | |
| 820 | test "os.getEnvVarOwned" { | |
| 821 | var ga = debug.global_allocator; | |
| 822 | debug.assertError(getEnvVarOwned(ga, "BADENV"), error.EnvironmentVariableNotFound); | |
| 823 | } | |
| 824 | ||
| 803 | 825 | /// Caller must free the returned memory. |
| 804 | 826 | pub fn getCwdAlloc(allocator: *Allocator) ![]u8 { |
| 805 | 827 | var buf: [MAX_PATH_BYTES]u8 = undefined; |
std/os/windows/kernel32.zig+3-3| ... | ... | @@ -50,7 +50,7 @@ pub extern "kernel32" stdcallcc fn FindFirstFileW(lpFileName: [*]const u16, lpFi |
| 50 | 50 | pub extern "kernel32" stdcallcc fn FindClose(hFindFile: HANDLE) BOOL; |
| 51 | 51 | pub extern "kernel32" stdcallcc fn FindNextFileW(hFindFile: HANDLE, lpFindFileData: *WIN32_FIND_DATAW) BOOL; |
| 52 | 52 | |
| 53 | pub extern "kernel32" stdcallcc fn FreeEnvironmentStringsA(penv: [*]u8) BOOL; | |
| 53 | pub extern "kernel32" stdcallcc fn FreeEnvironmentStringsW(penv: [*]u16) BOOL; | |
| 54 | 54 | |
| 55 | 55 | pub extern "kernel32" stdcallcc fn GetCommandLineA() LPSTR; |
| 56 | 56 | |
| ... | ... | @@ -63,9 +63,9 @@ pub extern "kernel32" stdcallcc fn GetCurrentDirectoryW(nBufferLength: DWORD, lp |
| 63 | 63 | pub extern "kernel32" stdcallcc fn GetCurrentThread() HANDLE; |
| 64 | 64 | pub extern "kernel32" stdcallcc fn GetCurrentThreadId() DWORD; |
| 65 | 65 | |
| 66 | pub extern "kernel32" stdcallcc fn GetEnvironmentStringsA() ?[*]u8; | |
| 66 | pub extern "kernel32" stdcallcc fn GetEnvironmentStringsW() ?[*]u16; | |
| 67 | 67 | |
| 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; | |
| 69 | 69 | |
| 70 | 70 | pub extern "kernel32" stdcallcc fn GetExitCodeProcess(hProcess: HANDLE, lpExitCode: *DWORD) BOOL; |
| 71 | 71 |