const std = #import("std"); const Allocator = std.Allocator; const current = #import("builtin").os; const system = switch (current) { .linux => linux, .macos => macos, .windows => windows, }; const exit = fn(exit_code: s32) noreturn { switch (current) { .linux => _ = #syscall(231, exit_code), .macos => macos.exit(exit_code), .windows => windows.ExitProcess(exit_code), } unreachable; } const ProcessId = system.ProcessId; const ProtectionFlags = struct(u32){ read: bool, write: bool, execute: bool, }; const MapFlags = struct(u32){ reserve: bool, commit: bool, }; const allocate_virtual_memory = fn(address: ?[&]u8, length: usize, general_protection_flags: ProtectionFlags, general_map_flags: MapFlags) ?[&]u8 { const protection_flags = system.get_protection_flags(flags = general_protection_flags); const map_flags = system.get_map_flags(flags = general_map_flags); switch (current) { .linux => { if (linux.unwrapSyscall(syscall_result = linux.mmap(address, length, protection_flags, map_flags, fd = -1, offset = 0))) |result_address| { const pointer: [&]u8 = #cast(result_address); return pointer; } else { return null; } }, else => #error("OS not supported"), } } const free_virtual_memory = fn(bytes_ptr: [&]const u8, bytes_len: usize) bool { switch (current) { .linux => { if (linux.unwrapSyscall(syscall_result = linux.munmap(bytes_ptr, bytes_len))) |result| { return result == 0; } else { return false; } }, else => #error("OS not supported"), } } const readlink = fn(file_path: [&:0]const u8, buffer: []u8) ?[]u8 { switch (current) { .linux => { const raw_result = linux.readlink(file_path, bytes_ptr = buffer.ptr, bytes_len = buffer.len); if (linux.unwrapSyscall(syscall_result = raw_result)) |byte_count| { const bytes = buffer[0..byte_count]; return bytes; } else { return null; } }, else => #error("OS not supported"), } } const max_path_byte_count = switch (current) { .linux => 0x1000, else => #error("OS not supported"), }; const current_executable_path = fn(allocator: &Allocator) ?[]u8 { switch (current) { .linux => { var buffer: [max_path_byte_count]u8 = undefined; if (readlink(file_path = "/proc/self/exe", buffer = buffer.&)) |bytes| { if (allocator.duplicate_bytes(bytes)) |result| { return result; } else { return null; } } else { return null; } }, else => #error("OS not supported"), } } const duplicate_process = fn () ?ProcessId { switch (current) { .linux => { if (linux.unwrapSyscall(syscall_result = linux.fork())) |fork_result| { return #cast(fork_result); } else { return null; } }, else => #error("OS not supported"), } } const FileDescriptor = struct{ handle: system.FileDescriptor, const write = fn (file_descriptor: FileDescriptor, bytes: []const u8) ?usize { switch (current) { .linux => { const raw_result = #syscall(1, file_descriptor.handle, #cast(bytes.ptr), bytes.len); if (linux.unwrapSyscall(syscall_result = raw_result)) |byte_count| { return byte_count; } else { return null; } }, else => #error("OS not supported"), } } }; const StdFileDescriptor = enum { stdin = 0, stdout = 1, stderr = 2, const get = fn(descriptor: StdFileDescriptor) FileDescriptor{ switch (current) { .linux, .macos => { return FileDescriptor{ .handle = #cast(descriptor), }; }, else => #error("OS not supported"), } } }; const linux = #import("os/linux.nat"); const macos = #import("os/macos.nat"); const windows = #import("os/windows.nat");