authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2022-05-11 15:33:04-04:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2022-05-11 15:33:04-04:00
log19003de64cfc6ea0b760998acee340c893075882
treec47e09ff538741007c3d9b60d6b1587ae98a9d8e
parent090461a6959ccebbc0c79cacebcf52bc43d66b9e
parent83a486a064fdb7a533d2bdac6f8b4b0e42e46546
signaturebadge-question-mark Signed by PGP key 4AEE18F83AFDEB23

Merge pull request #10595 from squeek502/getenvW-case

os.getenvW: Fix case-insensitivity for Unicode env var names

2 files changed, 28 insertions(+), 15 deletions(-)

lib/std/os.zig+22-15
......@@ -1883,19 +1883,23 @@ pub fn getenvZ(key: [*:0]const u8) ?[]const u8 {
18831883
18841884/// Windows-only. Get an environment variable with a null-terminated, WTF-16 encoded name.
18851885/// See also `getenv`.
1886/// This function first attempts a case-sensitive lookup. If no match is found, and `key`
1887/// is ASCII, then it attempts a second case-insensitive lookup.
1886/// This function performs a Unicode-aware case-insensitive lookup using RtlEqualUnicodeString.
18881887pub fn getenvW(key: [*:0]const u16) ?[:0]const u16 {
18891888 if (builtin.os.tag != .windows) {
18901889 @compileError("std.os.getenvW is a Windows-only API");
18911890 }
18921891 const key_slice = mem.sliceTo(key, 0);
18931892 const ptr = windows.peb().ProcessParameters.Environment;
1894 var ascii_match: ?[:0]const u16 = null;
18951893 var i: usize = 0;
18961894 while (ptr[i] != 0) {
18971895 const key_start = i;
18981896
1897 // There are some special environment variables that start with =,
1898 // so we need a special case to not treat = as a key/value separator
1899 // if it's the first character.
1900 // https://devblogs.microsoft.com/oldnewthing/20100506-00/?p=14133
1901 if (ptr[key_start] == '=') i += 1;
1902
18991903 while (ptr[i] != 0 and ptr[i] != '=') : (i += 1) {}
19001904 const this_key = ptr[key_start..i];
19011905
......@@ -1905,22 +1909,25 @@ pub fn getenvW(key: [*:0]const u16) ?[:0]const u16 {
19051909 while (ptr[i] != 0) : (i += 1) {}
19061910 const this_value = ptr[value_start..i :0];
19071911
1908 if (mem.eql(u16, key_slice, this_key)) return this_value;
1909
1910 ascii_check: {
1911 if (ascii_match != null) break :ascii_check;
1912 if (key_slice.len != this_key.len) break :ascii_check;
1913 for (key_slice) |a_c, key_index| {
1914 const a = math.cast(u8, a_c) catch break :ascii_check;
1915 const b = math.cast(u8, this_key[key_index]) catch break :ascii_check;
1916 if (std.ascii.toLower(a) != std.ascii.toLower(b)) break :ascii_check;
1917 }
1918 ascii_match = this_value;
1912 const key_string_bytes = @intCast(u16, key_slice.len * 2);
1913 const key_string = windows.UNICODE_STRING{
1914 .Length = key_string_bytes,
1915 .MaximumLength = key_string_bytes,
1916 .Buffer = @intToPtr([*]u16, @ptrToInt(key)),
1917 };
1918 const this_key_string_bytes = @intCast(u16, this_key.len * 2);
1919 const this_key_string = windows.UNICODE_STRING{
1920 .Length = this_key_string_bytes,
1921 .MaximumLength = this_key_string_bytes,
1922 .Buffer = this_key.ptr,
1923 };
1924 if (windows.ntdll.RtlEqualUnicodeString(&key_string, &this_key_string, windows.TRUE) == windows.TRUE) {
1925 return this_value;
19191926 }
19201927
19211928 i += 1; // skip over null byte
19221929 }
1923 return ascii_match;
1930 return null;
19241931}
19251932
19261933pub const GetCwdError = error{
lib/std/os/windows/ntdll.zig+6
......@@ -223,6 +223,12 @@ pub extern "ntdll" fn RtlWaitOnAddress(
223223 Timeout: ?*const LARGE_INTEGER,
224224) callconv(WINAPI) NTSTATUS;
225225
226pub extern "ntdll" fn RtlEqualUnicodeString(
227 String1: *const UNICODE_STRING,
228 String2: *const UNICODE_STRING,
229 CaseInSensitive: BOOLEAN,
230) callconv(WINAPI) BOOLEAN;
231
226232pub extern "ntdll" fn NtLockFile(
227233 FileHandle: HANDLE,
228234 Event: ?HANDLE,