| ... | ... | @@ -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,50 @@ 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 | |
| 716 | const stack_var_len = 50; |
| 717 | const key_slice = ptr[key_start..i]; |
| 718 | var key: []u8 = undefined; |
| 719 | var heap_key = false; |
| 720 | |
| 721 | // parse the key on the stack if smaller than 'stack_var_len' |
| 722 | if (key_slice.len < stack_var_len-@sizeOf(usize)) { |
| 723 | var buf = []u8{0} ** stack_var_len; |
| 724 | var fallocator = &std.heap.FixedBufferAllocator.init(buf[0..]).allocator; |
| 725 | key = try std.unicode.utf16leToUtf8Alloc(fallocator, key_slice); |
| 726 | } else { |
| 727 | key = try std.unicode.utf16leToUtf8Alloc(allocator, key_slice); |
| 728 | heap_key = true; // key needs to outlive this scope, so we cannot defer |
| 729 | } |
| 716 | 730 | |
| 717 | 731 | if (ptr[i] == '=') i += 1; |
| 718 | 732 | |
| 719 | 733 | const value_start = i; |
| 720 | 734 | while (ptr[i] != 0) : (i += 1) {} |
| 721 | | const value = ptr[value_start..i]; |
| 735 | |
| 736 | const value_slice = ptr[value_start..i]; |
| 737 | var value: []u8 = undefined; |
| 738 | var heap_value = false; |
| 739 | |
| 740 | if (value_slice.len < stack_var_len-@sizeOf(usize)) { |
| 741 | var buf = []u8{0} ** stack_var_len; |
| 742 | var fallocator = &std.heap.FixedBufferAllocator.init(buf[0..]).allocator; |
| 743 | value = try std.unicode.utf16leToUtf8Alloc(fallocator, value_slice); |
| 744 | } else { |
| 745 | value = try std.unicode.utf16leToUtf8Alloc(allocator, value_slice); |
| 746 | heap_value = true; // value needs to outlive this scope, so we cannot defer |
| 747 | } |
| 722 | 748 | |
| 723 | 749 | i += 1; // skip over null byte |
| 724 | 750 | |
| 725 | 751 | try result.set(key, value); |
| 752 | |
| 753 | if (heap_key) { |
| 754 | allocator.free(key); |
| 755 | } |
| 756 | if (heap_value) { |
| 757 | allocator.free(value); |
| 758 | } |
| 726 | 759 | } |
| 727 | 760 | } else { |
| 728 | 761 | for (posix_environ_raw) |ptr| { |
| ... | ... | @@ -740,6 +773,19 @@ pub fn getEnvMap(allocator: *Allocator) !BufMap { |
| 740 | 773 | } |
| 741 | 774 | } |
| 742 | 775 | |
| 776 | test "os.getEnvMap" { |
| 777 | var env = try getEnvMap(std.debug.global_allocator); |
| 778 | var seen_path = false; |
| 779 | var it = env.iterator(); |
| 780 | while (it.next()) |pair| { |
| 781 | if (mem.eql(u8, pair.key, "PATH")) { |
| 782 | seen_path = true; |
| 783 | } |
| 784 | } |
| 785 | |
| 786 | assert(seen_path == true); |
| 787 | } |
| 788 | |
| 743 | 789 | /// TODO make this go through libc when we have it |
| 744 | 790 | pub fn getEnvPosix(key: []const u8) ?[]const u8 { |
| 745 | 791 | for (posix_environ_raw) |ptr| { |
| ... | ... | @@ -760,21 +806,27 @@ pub fn getEnvPosix(key: []const u8) ?[]const u8 { |
| 760 | 806 | pub const GetEnvVarOwnedError = error{ |
| 761 | 807 | OutOfMemory, |
| 762 | 808 | EnvironmentVariableNotFound, |
| 809 | DanglingSurrogateHalf, |
| 810 | ExpectedSecondSurrogateHalf, |
| 811 | UnexpectedSecondSurrogateHalf, |
| 812 | |
| 813 | /// See https://github.com/ziglang/zig/issues/1774 |
| 814 | InvalidUtf8, |
| 763 | 815 | }; |
| 764 | 816 | |
| 765 | 817 | /// Caller must free returned memory. |
| 766 | 818 | /// TODO make this go through libc when we have it |
| 767 | 819 | pub fn getEnvVarOwned(allocator: *mem.Allocator, key: []const u8) GetEnvVarOwnedError![]u8 { |
| 768 | 820 | if (is_windows) { |
| 769 | | const key_with_null = try cstr.addNullByte(allocator, key); |
| 821 | const key_with_null = try std.unicode.utf8ToUtf16LeWithNull(allocator, key); |
| 770 | 822 | defer allocator.free(key_with_null); |
| 771 | 823 | |
| 772 | | var buf = try allocator.alloc(u8, 256); |
| 773 | | errdefer allocator.free(buf); |
| 824 | var buf = try allocator.alloc(u16, 256); |
| 825 | defer allocator.free(buf); |
| 774 | 826 | |
| 775 | 827 | while (true) { |
| 776 | 828 | 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); |
| 829 | const result = windows.GetEnvironmentVariableW(key_with_null.ptr, buf.ptr, windows_buf_len); |
| 778 | 830 | |
| 779 | 831 | if (result == 0) { |
| 780 | 832 | const err = windows.GetLastError(); |
| ... | ... | @@ -788,11 +840,11 @@ pub fn getEnvVarOwned(allocator: *mem.Allocator, key: []const u8) GetEnvVarOwned |
| 788 | 840 | } |
| 789 | 841 | |
| 790 | 842 | if (result > buf.len) { |
| 791 | | buf = try allocator.realloc(u8, buf, result); |
| 843 | buf = try allocator.realloc(u16, buf, result); |
| 792 | 844 | continue; |
| 793 | 845 | } |
| 794 | 846 | |
| 795 | | return allocator.shrink(u8, buf, result); |
| 847 | return try std.unicode.utf16leToUtf8Alloc(allocator, buf); |
| 796 | 848 | } |
| 797 | 849 | } else { |
| 798 | 850 | const result = getEnvPosix(key) orelse return error.EnvironmentVariableNotFound; |
| ... | ... | @@ -800,6 +852,15 @@ pub fn getEnvVarOwned(allocator: *mem.Allocator, key: []const u8) GetEnvVarOwned |
| 800 | 852 | } |
| 801 | 853 | } |
| 802 | 854 | |
| 855 | test "os.getEnvVarOwned" { |
| 856 | switch (builtin.os) { |
| 857 | builtin.Os.windows, builtin.Os.linux, builtin.Os.macosx, |
| 858 | builtin.Os.ios => _ = try getEnvVarOwned(debug.global_allocator, "PATH"), |
| 859 | else => @compileError("unimplemented"), |
| 860 | } |
| 861 | } |
| 862 | |
| 863 | |
| 803 | 864 | /// Caller must free the returned memory. |
| 804 | 865 | pub fn getCwdAlloc(allocator: *Allocator) ![]u8 { |
| 805 | 866 | var buf: [MAX_PATH_BYTES]u8 = undefined; |