mirror of
https://codeberg.org/ziglang/zig.git
synced 2026-03-08 10:05:10 +01:00
78 lines
2.4 KiB
Zig
78 lines
2.4 KiB
Zig
const Preopens = @This();
|
|
|
|
const builtin = @import("builtin");
|
|
const native_os = builtin.os.tag;
|
|
|
|
const std = @import("../std.zig");
|
|
const Io = std.Io;
|
|
const Allocator = std.mem.Allocator;
|
|
|
|
map: Map,
|
|
|
|
pub const empty: Preopens = switch (native_os) {
|
|
.wasi => .{ .map = .empty },
|
|
else => .{ .map = {} },
|
|
};
|
|
|
|
pub const Map = switch (native_os) {
|
|
// Indexed by file descriptor number.
|
|
.wasi => std.StringArrayHashMapUnmanaged(void),
|
|
else => void,
|
|
};
|
|
|
|
pub const Resource = union(enum) {
|
|
file: Io.File,
|
|
dir: Io.Dir,
|
|
};
|
|
|
|
pub fn get(p: *const Preopens, name: []const u8) ?Resource {
|
|
switch (native_os) {
|
|
.wasi => {
|
|
const index = p.map.getIndex(name) orelse return null;
|
|
if (index <= 2) return .{ .file = .{
|
|
.handle = @intCast(index),
|
|
.flags = .{ .nonblocking = false },
|
|
} };
|
|
return .{ .dir = .{ .handle = @intCast(index) } };
|
|
},
|
|
else => {
|
|
if (std.mem.eql(u8, name, "stdin")) return .{ .file = .stdin() };
|
|
if (std.mem.eql(u8, name, "stdout")) return .{ .file = .stdout() };
|
|
if (std.mem.eql(u8, name, "stderr")) return .{ .file = .stderr() };
|
|
return null;
|
|
},
|
|
}
|
|
}
|
|
|
|
pub const InitError = Allocator.Error || error{Unexpected};
|
|
|
|
pub fn init(arena: Allocator) InitError!Preopens {
|
|
if (native_os != .wasi) return .{ .map = {} };
|
|
const wasi = std.os.wasi;
|
|
var map: Map = .empty;
|
|
|
|
try map.ensureUnusedCapacity(arena, 3);
|
|
|
|
map.putAssumeCapacityNoClobber("stdin", {}); // 0
|
|
map.putAssumeCapacityNoClobber("stdout", {}); // 1
|
|
map.putAssumeCapacityNoClobber("stderr", {}); // 2
|
|
while (true) {
|
|
const fd: wasi.fd_t = @intCast(map.entries.len);
|
|
var prestat: wasi.prestat_t = undefined;
|
|
switch (wasi.fd_prestat_get(fd, &prestat)) {
|
|
.SUCCESS => {},
|
|
.OPNOTSUPP, .BADF => return .{ .map = map },
|
|
else => return error.Unexpected,
|
|
}
|
|
try map.ensureUnusedCapacity(arena, 1);
|
|
// This length does not include a null byte. Let's keep it this way to
|
|
// gently encourage WASI implementations to behave properly.
|
|
const name_len = prestat.u.dir.pr_name_len;
|
|
const name = try arena.alloc(u8, name_len);
|
|
switch (wasi.fd_prestat_dir_name(fd, name.ptr, name.len)) {
|
|
.SUCCESS => {},
|
|
else => return error.Unexpected,
|
|
}
|
|
map.putAssumeCapacityNoClobber(name, {});
|
|
}
|
|
}
|