zig/std/os/windows/util.zig
2019-05-26 18:32:40 -04:00

150 lines
5.2 KiB
Zig

const std = @import("../../std.zig");
const builtin = @import("builtin");
const os = std.os;
const unicode = std.unicode;
const windows = std.os.windows;
const assert = std.debug.assert;
const mem = std.mem;
const BufMap = std.BufMap;
const cstr = std.cstr;
pub const WaitError = error{
WaitAbandoned,
WaitTimeOut,
/// See https://github.com/ziglang/zig/issues/1396
Unexpected,
};
pub fn windowsWaitSingle(handle: windows.HANDLE, milliseconds: windows.DWORD) WaitError!void {
const result = windows.WaitForSingleObject(handle, milliseconds);
return switch (result) {
windows.WAIT_ABANDONED => error.WaitAbandoned,
windows.WAIT_OBJECT_0 => {},
windows.WAIT_TIMEOUT => error.WaitTimeOut,
windows.WAIT_FAILED => x: {
const err = windows.GetLastError();
break :x switch (err) {
else => os.unexpectedErrorWindows(err),
};
},
else => error.Unexpected,
};
}
/// Caller must free result.
pub fn createWindowsEnvBlock(allocator: *mem.Allocator, env_map: *const BufMap) ![]u16 {
// count bytes needed
const max_chars_needed = x: {
var max_chars_needed: usize = 4; // 4 for the final 4 null bytes
var it = env_map.iterator();
while (it.next()) |pair| {
// +1 for '='
// +1 for null byte
max_chars_needed += pair.key.len + pair.value.len + 2;
}
break :x max_chars_needed;
};
const result = try allocator.alloc(u16, max_chars_needed);
errdefer allocator.free(result);
var it = env_map.iterator();
var i: usize = 0;
while (it.next()) |pair| {
i += try unicode.utf8ToUtf16Le(result[i..], pair.key);
result[i] = '=';
i += 1;
i += try unicode.utf8ToUtf16Le(result[i..], pair.value);
result[i] = 0;
i += 1;
}
result[i] = 0;
i += 1;
result[i] = 0;
i += 1;
result[i] = 0;
i += 1;
result[i] = 0;
i += 1;
return allocator.shrink(result, i);
}
pub fn windowsFindFirstFile(
dir_path: []const u8,
find_file_data: *windows.WIN32_FIND_DATAW,
) !windows.HANDLE {
const dir_path_w = try sliceToPrefixedSuffixedFileW(dir_path, []u16{ '\\', '*', 0 });
const handle = windows.FindFirstFileW(&dir_path_w, find_file_data);
if (handle == windows.INVALID_HANDLE_VALUE) {
const err = windows.GetLastError();
switch (err) {
windows.ERROR.FILE_NOT_FOUND => return error.FileNotFound,
windows.ERROR.PATH_NOT_FOUND => return error.FileNotFound,
else => return os.unexpectedErrorWindows(err),
}
}
return handle;
}
/// Returns `true` if there was another file, `false` otherwise.
pub fn windowsFindNextFile(handle: windows.HANDLE, find_file_data: *windows.WIN32_FIND_DATAW) !bool {
if (windows.FindNextFileW(handle, find_file_data) == 0) {
const err = windows.GetLastError();
return switch (err) {
windows.ERROR.NO_MORE_FILES => false,
else => os.unexpectedErrorWindows(err),
};
}
return true;
}
pub const WindowsCreateIoCompletionPortError = error{Unexpected};
pub fn windowsCreateIoCompletionPort(file_handle: windows.HANDLE, existing_completion_port: ?windows.HANDLE, completion_key: usize, concurrent_thread_count: windows.DWORD) !windows.HANDLE {
const handle = windows.CreateIoCompletionPort(file_handle, existing_completion_port, completion_key, concurrent_thread_count) orelse {
const err = windows.GetLastError();
switch (err) {
windows.ERROR.INVALID_PARAMETER => unreachable,
else => return os.unexpectedErrorWindows(err),
}
};
return handle;
}
pub const WindowsPostQueuedCompletionStatusError = error{Unexpected};
pub fn windowsPostQueuedCompletionStatus(completion_port: windows.HANDLE, bytes_transferred_count: windows.DWORD, completion_key: usize, lpOverlapped: ?*windows.OVERLAPPED) WindowsPostQueuedCompletionStatusError!void {
if (windows.PostQueuedCompletionStatus(completion_port, bytes_transferred_count, completion_key, lpOverlapped) == 0) {
const err = windows.GetLastError();
switch (err) {
else => return os.unexpectedErrorWindows(err),
}
}
}
pub const WindowsWaitResult = enum {
Normal,
Aborted,
Cancelled,
EOF,
};
pub fn windowsGetQueuedCompletionStatus(completion_port: windows.HANDLE, bytes_transferred_count: *windows.DWORD, lpCompletionKey: *usize, lpOverlapped: *?*windows.OVERLAPPED, dwMilliseconds: windows.DWORD) WindowsWaitResult {
if (windows.GetQueuedCompletionStatus(completion_port, bytes_transferred_count, lpCompletionKey, lpOverlapped, dwMilliseconds) == windows.FALSE) {
const err = windows.GetLastError();
switch (err) {
windows.ERROR.ABANDONED_WAIT_0 => return WindowsWaitResult.Aborted,
windows.ERROR.OPERATION_ABORTED => return WindowsWaitResult.Cancelled,
windows.ERROR.HANDLE_EOF => return WindowsWaitResult.EOF,
else => {
if (std.debug.runtime_safety) {
std.debug.panic("unexpected error: {}\n", err);
}
},
}
}
return WindowsWaitResult.Normal;
}