pub fn createWindowsBlock(
map: *const Map,
gpa: Allocator,
options: CreateWindowsBlockOptions,
) error{ OutOfMemory, InvalidWtf8 }!WindowsBlock {
// count bytes needed
const max_chars_needed = max_chars_needed: {
var max_chars_needed: usize = "\x00".len;
if (options.zig_progress_handle) |handle| if (handle != std.os.windows.INVALID_HANDLE_VALUE) {
max_chars_needed += std.fmt.count("ZIG_PROGRESS={d}\x00", .{@intFromPtr(handle)});
};
for (map.keys(), map.values()) |key, value| {
if (options.zig_progress_handle != null and eqlKeys(key, "ZIG_PROGRESS")) continue;
max_chars_needed += key.len + "=".len + value.len + "\x00".len;
}
break :max_chars_needed @max("\x00\x00".len, max_chars_needed);
};
const block = try gpa.alloc(u16, max_chars_needed);
errdefer gpa.free(block);
var i: usize = 0;
if (options.zig_progress_handle) |handle| if (handle != std.os.windows.INVALID_HANDLE_VALUE) {
@memcpy(
block[i..][0.."ZIG_PROGRESS=".len],
&[_]u16{ 'Z', 'I', 'G', '_', 'P', 'R', 'O', 'G', 'R', 'E', 'S', 'S', '=' },
);
i += "ZIG_PROGRESS=".len;
var value_buf: [std.fmt.count("{d}", .{std.math.maxInt(usize)})]u8 = undefined;
const value = std.mem.print(&value_buf, "{d}", .{@intFromPtr(handle)}) catch unreachable;
for (block[i..][0..value.len], value) |*r, v| r.* = v;
i += value.len;
block[i] = 0;
i += 1;
};
for (map.keys(), map.values()) |key, value| {
if (options.zig_progress_handle != null and eqlKeys(key, "ZIG_PROGRESS")) continue;
i += try unicode.wtf8ToWtf16Le(block[i..], key);
block[i] = '=';
i += 1;
i += try unicode.wtf8ToWtf16Le(block[i..], value);
block[i] = 0;
i += 1;
}
// An empty environment is a special case that requires a redundant
// NUL terminator. CreateProcess will read the second code unit even
// though theoretically the first should be enough to recognize that the
// environment is empty (see https://nullprogram.com/blog/2023/08/23/)
for (0..2) |_| {
block[i] = 0;
i += 1;
if (i >= 2) break;
} else unreachable;
const reallocated = try gpa.realloc(block, i);
return .{ .slice = reallocated[0 .. i - 1 :0] };
}
Caller owns result.