@@ -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,18 +800,28 @@ 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 ;
799
816
return mem .dupe (allocator , u8 , result );
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 ;
0 commit comments