Zig 0.17.0-dev (Split by item)

This is an example of documentation generated by ZigDoc, an alternative to Zig's built-in Auto Doc feature. See also examples in other modes/formats. The project being documented here (as the example) is the Zig library itself.

createWindowsBlock

Creates a null-delimited environment variable block in the format expected by POSIX, from a different one.

Environ.createWindowsBlock
pub fn createWindowsBlock(
    existing: Environ,
    gpa: Allocator,
    options: CreateWindowsBlockOptions,
) Allocator.Error!WindowsBlock

File

lib/std/process/Environ.zig:798

Code

pub fn createWindowsBlock(
    existing: Environ,
    gpa: Allocator,
    options: CreateWindowsBlockOptions,
) Allocator.Error!WindowsBlock {
    if (!existing.block.use_global) return .{
        .slice = try gpa.dupeSentinel(u16, WindowsBlock.empty.slice, 0),
    };
    const peb = std.os.windows.peb();
    assert(std.os.windows.ntdll.RtlEnterCriticalSection(peb.FastPebLock) == .SUCCESS);
    defer assert(std.os.windows.ntdll.RtlLeaveCriticalSection(peb.FastPebLock) == .SUCCESS);
    const existing_block = peb.ProcessParameters.Environment;
    var ranges: [2]struct { start: usize, end: usize } = undefined;
    var ranges_len: usize = 0;
    ranges[ranges_len].start = 0;
    const zig_progress_key = [_]u16{ 'Z', 'I', 'G', '_', 'P', 'R', 'O', 'G', 'R', 'E', 'S', 'S', '=' };
    const needed_len = needed_len: {
        var needed_len: usize = "\x00".len;
        if (options.zig_progress_handle) |handle| if (handle != std.os.windows.INVALID_HANDLE_VALUE) {
            needed_len += std.fmt.count("ZIG_PROGRESS={d}\x00", .{@intFromPtr(handle)});
        };
        var i: usize = 0;
        while (existing_block[i] != 0) {
            const start = i;
            const entry = mem.sliceTo(existing_block[start..], 0);
            i += entry.len + "\x00".len;
            if (options.zig_progress_handle != null and entry.len >= zig_progress_key.len and
                std.os.windows.eqlIgnoreCaseWtf16(entry[0..zig_progress_key.len], &zig_progress_key))
            {
                ranges[ranges_len].end = start;
                ranges_len += 1;
                ranges[ranges_len].start = i;
            } else needed_len += entry.len + "\x00".len;
        }
        ranges[ranges_len].end = i;
        ranges_len += 1;
        break :needed_len @max("\x00\x00".len, needed_len);
    };
    const block = try gpa.alloc(u16, needed_len);
    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_key.len], &zig_progress_key);
        i += zig_progress_key.len;
        var value_buf: [std.fmt.count("{d}", .{std.math.maxInt(usize)})]u8 = undefined;
        const value = std.fmt.bufPrint(&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 (ranges[0..ranges_len]) |range| {
        const range_len = range.end - range.start;
        @memcpy(block[i..][0..range_len], existing_block[range.start..range.end]);
        i += range_len;
    }
    // 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;
    assert(i == block.len);
    return .{ .slice = block[0 .. i - 1 :0] };
}