0

我正在尝试调用 iotcl 来获得这样的终端大小:

const std = @import("std");

fn ioctl_TIOCGWINSZ(fd: std.os.fd_t, ws: *std.os.linux.winsize) !void {
    while (true) {
        switch (std.os.errno(std.os.linux.ioctl(fd, std.os.linux.T.IOCGWINSZ, @ptrToInt(ws)))) {
            .SUCCESS => return,
            .INTR => continue,
            .INVAL => unreachable, // invalid request or argument
            .BADF => unreachable,  // fd is not a file descriptor
            .FAULT => unreachable, // invalid argument
            .NOTTY => return std.os.TermiosGetError.NotATerminal, //  fd is not a tty
            else => |err| return std.os.unexpectedErrno(err),
        }
    }
}

pub fn getTerminalSize(handle: std.os.fd_t) !type {

    var size : std.os.linux.winsize = undefined;
    try ioctl_TIOCGWINSZ(handle, &size);

    return .{ size.ws_col, size.ws_row };
}

呼吁getTerminalSize成为:

    var size = try tz.getTerminalSize(std.os.STDOUT_FILENO);

但是,这会产生如下编译器错误:

./libs/terz/terminal.zig:40:79: error: unable to evaluate constant expression
        switch (std.os.errno(std.os.linux.ioctl(fd, std.os.linux.T.IOCGWINSZ, @ptrToInt(ws)))) {
                                                                              ^
./libs/terz/terminal.zig:55:25: note: called from here
    try ioctl_TIOCGWINSZ(handle, &size);
                        ^
./src/main.zig:15:42: note: called from here
        var size = try tz.getTerminalSize(std.os.STDOUT_FILENO);
                                         ^
./src/main.zig:5:29: note: called from here
pub fn main() anyerror!void {
                            ^
./libs/terz/terminal.zig:40:48: note: referenced here
        switch (std.os.errno(std.os.linux.ioctl(fd, std.os.linux.T.IOCGWINSZ, @ptrToInt(ws)))) {
                                               ^
./libs/terz/terminal.zig:55:25: note: referenced here
    try ioctl_TIOCGWINSZ(handle, &size);
                        ^
./src/main.zig:15:42: note: referenced here
        var size = try tz.getTerminalSize(std.os.STDOUT_FILENO);
                                         ^

std/os/linux.zig中,ioctl定义为:

pub fn ioctl(fd: fd_t, request: u32, arg: usize) usize {
    return syscall3(.ioctl, @bitCast(usize, @as(isize, fd)), request, arg);
}

并且std.os.zig有一个类似于我正在尝试做的功能(可能有效):

pub fn ioctl_SIOCGIFINDEX(fd: fd_t, ifr: *ifreq) IoCtl_SIOCGIFINDEX_Error!void {
    while (true) {
        switch (errno(system.ioctl(fd, SIOCGIFINDEX, @ptrToInt(ifr)))) {
            .SUCCESS => return,
            .INVAL => unreachable, // Bad parameters.
            .NOTTY => unreachable,
            .NXIO => unreachable,
            .BADF => unreachable, // Always a race condition.
            .FAULT => unreachable, // Bad pointer parameter.
            .INTR => continue,
            .IO => return error.FileSystem,
            .NODEV => return error.InterfaceNotFound,
            else => |err| return unexpectedErrno(err),
        }
    }
}

这是编译器错误,还是我做错了什么?

谢谢!

4

1 回答 1

0

所以看起来 my 有一些问题getTerminalSize(),并且错误消息指向了错误的罪魁祸首。

getTerminalSize()不应该回来type。要返回匿名结构,语法为:

pub fn getTerminalSize(handle: std.os.fd_t) !struct{ width: u16, height: u16 } {

    var size : std.os.linux.winsize = undefined;
    try ioctl_TIOCGWINSZ(handle, &size);

    return .{ .width = size.ws_col, .height = size.ws_row };
}

但是,zig 目前不支持返回与错误类型联合的匿名结构

So for the moment, the solution is to name the struct:

pub const TerminalSize = struct {
    width: u16,
    height: u16,
};

pub fn getTerminalSize(handle: std.os.fd_t) !TerminalSize {

    var size: std.os.linux.winsize = undefined;
    try ioctl_TIOCGWINSZ(handle, &size);

    return TerminalSize{ .width = size.ws_col, .height = size.ws_row };
}
于 2021-11-24T12:00:39.000 回答