From 8bf7cffe29b520cda094756309bca1d354af0d6b Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Thu, 2 Apr 2020 15:04:42 -0400 Subject: [PATCH] slight modification of the semantics of std.os.getenvW Now, this function first attempts a case-sensitive lookup. If no match is found, and `key` is ASCII, then it attempts a second case-insensitive lookup. It is not planned to support full Unicode case-insensitivity on Windows, and in fact relying on non-ASCII case-insensitive environment variables is fundamentally problematic. --- lib/std/os.zig | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/lib/std/os.zig b/lib/std/os.zig index 07d4c19a8..bb206b289 100644 --- a/lib/std/os.zig +++ b/lib/std/os.zig @@ -21,7 +21,6 @@ const assert = std.debug.assert; const math = std.math; const mem = std.mem; const elf = std.elf; -const unicode = std.unicode; const dl = @import("dynamic_library.zig"); const MAX_PATH_BYTES = std.fs.MAX_PATH_BYTES; @@ -1207,27 +1206,17 @@ pub fn getenvZ(key: [*:0]const u8) ?[]const u8 { return getenv(mem.spanZ(key)); } -fn utf16LeAsciiEqlIgnoreCase(a: []const u16, b: []const u16) bool { - if (a.len != b.len) return false; - var a_it = unicode.Utf16LeIterator.init(a); - var b_it = unicode.Utf16LeIterator.init(b); - while (a_it.nextCodepoint() catch return false) |a_codepoint| { - const b_codepoint = (b_it.nextCodepoint() catch return false) orelse return false; - const upper_a = if (a_codepoint >= 97 and a_codepoint <= 122) a_codepoint & 0b11011111 else a_codepoint; - const upper_b = if (b_codepoint >= 97 and b_codepoint <= 122) b_codepoint & 0b11011111 else b_codepoint; - if (upper_a != upper_b) return false; - } - return true; -} - /// Windows-only. Get an environment variable with a null-terminated, WTF-16 encoded name. /// See also `getenv`. +/// This function first attempts a case-sensitive lookup. If no match is found, and `key` +/// is ASCII, then it attempts a second case-insensitive lookup. pub fn getenvW(key: [*:0]const u16) ?[:0]const u16 { if (builtin.os.tag != .windows) { @compileError("std.os.getenvW is a Windows-only API"); } const key_slice = mem.spanZ(key); const ptr = windows.peb().ProcessParameters.Environment; + var ascii_match: ?[:0]const u16 = null; var i: usize = 0; while (ptr[i] != 0) { const key_start = i; @@ -1241,11 +1230,22 @@ pub fn getenvW(key: [*:0]const u16) ?[:0]const u16 { while (ptr[i] != 0) : (i += 1) {} const this_value = ptr[value_start..i :0]; - if (utf16LeAsciiEqlIgnoreCase(key_slice, this_key)) return this_value; + if (mem.eql(u16, key_slice, this_key)) return this_value; + + ascii_check: { + if (ascii_match != null) break :ascii_check; + if (key_slice.len != this_key.len) break :ascii_check; + for (key_slice) |a_c, key_index| { + const a = math.cast(u8, a_c) catch break :ascii_check; + const b = math.cast(u8, this_key[key_index]) catch break :ascii_check; + if (std.ascii.toLower(a) != std.ascii.toLower(b)) break :ascii_check; + } + ascii_match = this_value; + } i += 1; // skip over null byte } - return null; + return ascii_match; } pub const GetCwdError = error{