| ... | ... | @@ -702,27 +702,57 @@ 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 | |
| 708 | var buf: [100]u8 = undefined; |
| 707 | 709 | |
| 708 | 710 | var i: usize = 0; |
| 709 | 711 | while (true) { |
| 710 | 712 | if (ptr[i] == 0) return result; |
| 711 | 713 | |
| 712 | 714 | const key_start = i; |
| 715 | var fallocator = &std.heap.FixedBufferAllocator.init(buf[0..]).allocator; |
| 713 | 716 | |
| 714 | 717 | while (ptr[i] != 0 and ptr[i] != '=') : (i += 1) {} |
| 715 | | const key = ptr[key_start..i]; |
| 718 | |
| 719 | const key_slice = ptr[key_start..i]; |
| 720 | var key: []u8 = undefined; |
| 721 | var heap_key = false; |
| 722 | |
| 723 | key = std.unicode.utf16leToUtf8Alloc(fallocator, key_slice) catch undefined; |
| 724 | |
| 725 | if (key.len == 0) { |
| 726 | key = try std.unicode.utf16leToUtf8Alloc(allocator, key_slice); |
| 727 | heap_key = true; |
| 728 | } |
| 716 | 729 | |
| 717 | 730 | if (ptr[i] == '=') i += 1; |
| 718 | 731 | |
| 719 | 732 | const value_start = i; |
| 720 | 733 | while (ptr[i] != 0) : (i += 1) {} |
| 721 | | const value = ptr[value_start..i]; |
| 734 | |
| 735 | const value_slice = ptr[value_start..i]; |
| 736 | var value: []u8 = undefined; |
| 737 | var heap_value = false; |
| 738 | |
| 739 | value = std.unicode.utf16leToUtf8Alloc(fallocator, value_slice) catch undefined; |
| 740 | |
| 741 | if (value.len == 0) { |
| 742 | value = try std.unicode.utf16leToUtf8Alloc(allocator, value_slice); |
| 743 | heap_value = true; |
| 744 | } |
| 722 | 745 | |
| 723 | 746 | i += 1; // skip over null byte |
| 724 | 747 | |
| 725 | 748 | try result.set(key, value); |
| 749 | |
| 750 | if (heap_key) { |
| 751 | allocator.free(key); |
| 752 | } |
| 753 | if (heap_value) { |
| 754 | allocator.free(value); |
| 755 | } |
| 726 | 756 | } |
| 727 | 757 | } else { |
| 728 | 758 | for (posix_environ_raw) |ptr| { |
| ... | ... | @@ -740,6 +770,11 @@ pub fn getEnvMap(allocator: *Allocator) !BufMap { |
| 740 | 770 | } |
| 741 | 771 | } |
| 742 | 772 | |
| 773 | test "os.getEnvMap" { |
| 774 | var env = try getEnvMap(std.debug.global_allocator); |
| 775 | defer env.deinit(); |
| 776 | } |
| 777 | |
| 743 | 778 | /// TODO make this go through libc when we have it |
| 744 | 779 | pub fn getEnvPosix(key: []const u8) ?[]const u8 { |
| 745 | 780 | for (posix_environ_raw) |ptr| { |
| ... | ... | @@ -760,21 +795,27 @@ pub fn getEnvPosix(key: []const u8) ?[]const u8 { |
| 760 | 795 | pub const GetEnvVarOwnedError = error{ |
| 761 | 796 | OutOfMemory, |
| 762 | 797 | EnvironmentVariableNotFound, |
| 798 | DanglingSurrogateHalf, |
| 799 | ExpectedSecondSurrogateHalf, |
| 800 | UnexpectedSecondSurrogateHalf, |
| 801 | |
| 802 | /// See https://github.com/ziglang/zig/issues/1774 |
| 803 | InvalidUtf8, |
| 763 | 804 | }; |
| 764 | 805 | |
| 765 | 806 | /// Caller must free returned memory. |
| 766 | 807 | /// TODO make this go through libc when we have it |
| 767 | 808 | pub fn getEnvVarOwned(allocator: *mem.Allocator, key: []const u8) GetEnvVarOwnedError![]u8 { |
| 768 | 809 | if (is_windows) { |
| 769 | | const key_with_null = try cstr.addNullByte(allocator, key); |
| 810 | const key_with_null = try std.unicode.utf8ToUtf16LeWithNull(allocator, key); |
| 770 | 811 | defer allocator.free(key_with_null); |
| 771 | 812 | |
| 772 | | var buf = try allocator.alloc(u8, 256); |
| 773 | | errdefer allocator.free(buf); |
| 813 | var buf = try allocator.alloc(u16, 256); |
| 814 | defer allocator.free(buf); |
| 774 | 815 | |
| 775 | 816 | while (true) { |
| 776 | 817 | 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); |
| 818 | const result = windows.GetEnvironmentVariableW(key_with_null.ptr, buf.ptr, windows_buf_len); |
| 778 | 819 | |
| 779 | 820 | if (result == 0) { |
| 780 | 821 | const err = windows.GetLastError(); |
| ... | ... | @@ -788,11 +829,11 @@ pub fn getEnvVarOwned(allocator: *mem.Allocator, key: []const u8) GetEnvVarOwned |
| 788 | 829 | } |
| 789 | 830 | |
| 790 | 831 | if (result > buf.len) { |
| 791 | | buf = try allocator.realloc(u8, buf, result); |
| 832 | buf = try allocator.realloc(u16, buf, result); |
| 792 | 833 | continue; |
| 793 | 834 | } |
| 794 | 835 | |
| 795 | | return allocator.shrink(u8, buf, result); |
| 836 | return try std.unicode.utf16leToUtf8Alloc(allocator, buf); |
| 796 | 837 | } |
| 797 | 838 | } else { |
| 798 | 839 | const result = getEnvPosix(key) orelse return error.EnvironmentVariableNotFound; |
| ... | ... | @@ -800,6 +841,12 @@ pub fn getEnvVarOwned(allocator: *mem.Allocator, key: []const u8) GetEnvVarOwned |
| 800 | 841 | } |
| 801 | 842 | } |
| 802 | 843 | |
| 844 | test "os.getEnvVarOwned" { |
| 845 | var ga = debug.global_allocator; |
| 846 | debug.assertError(getEnvVarOwned(ga, "BADENV"), error.EnvironmentVariableNotFound); |
| 847 | } |
| 848 | |
| 849 | |
| 803 | 850 | /// Caller must free the returned memory. |
| 804 | 851 | pub fn getCwdAlloc(allocator: *Allocator) ![]u8 { |
| 805 | 852 | var buf: [MAX_PATH_BYTES]u8 = undefined; |