I want to use ioctl to get winsize. i have c code but dont get zig

c code i have to get in zig

int main() {
    struct winsize ws;
    if (ioctl(STDOUT_FILENO, TIOCGWINSZ, &ws) == -1) {
        perror("ioctl");
        return 1;
    }
    printf("Rows: %d, Cols: %d\n", ws.ws_row, ws.ws_col);
    return 0;
} 

please do help me :folded_hands:

An example from std.Progress:

(posix here is std.posix FYI)

1 Like

what is the type or what should i pass in as fd

The type is std.posix.fd_t. If you wanted to match your C code you could use std.io.getStdOut().handle

why does. row and. col, 0. when i run this?

b must be a var.

    var b: std.posix.winsize = .{ ...

oh, i missed that. thank you :folded_hands:

1 Like

cross platform approach below and includes lldb compatable terminal contexts.

const TIOCGWINSZ = std.c.T.IOCGWINSZ;
const TermSz = struct { height: usize, width: usize };


pub fn getTermSzWin() !TermSz {
    //Microsoft Windows Case
    var info: win32.CONSOLE_SCREEN_BUFFER_INFO = .{ .dwSize = .{ .X = 0, .Y = 0 },
                                                    .dwCursorPosition = .{.X= 0, .Y= 0},
                                                    .wAttributes= 0,
                                                    .srWindow = .{ .Left = 0, .Top = 0, .Right = 0, .Bottom = 0},
                                                    .dwMaximumWindowSize = .{.X = 0, .Y = 0} };

    if (0 == win32.GetConsoleScreenBufferInfo(g_tty_win, &info)) switch (std.os.windows.kernel32.GetLastError()) {
        else => |e| return std.os.windows.unexpectedError(e),
    };

    return TermSz{
        .height = @intCast(info.srWindow.Bottom - info.srWindow.Top + 1),
        .width = @intCast(info.srWindow.Right - info.srWindow.Left + 1),
    };
}

pub fn getTermSzLinux() !TermSz {
    //Linux-MacOS Case

    //base case - invoked from cmd line
    const tty_nix = stdout.context.handle;
    var winsz = std.c.winsize{ .col = 0, .row = 0, .xpixel = 0, .ypixel = 0 };
    const rv = std.c.ioctl(tty_nix, TIOCGWINSZ, @intFromPtr(&winsz));
    const err = std.posix.errno(rv);

    if (rv >= 0) {
        if (winsz.row == 0 or winsz.col == 0) { // ltty IOCTL failed ie in lldb
            //alt case - invoked from inside lldb
            var lldb_tty_nix = try std.fs.cwd().openFile("/dev/tty", .{});
            defer lldb_tty_nix.close();

            var lldb_winsz = std.c.winsize{ .col = 0, .row = 0, .xpixel = 0, .ypixel = 0 };
            const lldb_rv = std.c.ioctl(lldb_tty_nix.handle, TIOCGWINSZ, @intFromPtr(&lldb_winsz));
            const lldb_err = std.posix.errno(lldb_rv);

            if (lldb_rv >= 0) {
                return TermSz{ .height = lldb_winsz.row, .width = lldb_winsz.col };
            } else {
                std.process.exit(0);
                //TODO this is a pretty terrible way to handle issues...
                return std.posix.unexpectedErrno(lldb_err);
            }
        } else {
            return TermSz{ .height = winsz.row, .width = winsz.col };
        }
    } else {
        std.process.exit(0);
        //TODO this is a pretty terrible way to handle issues...
        return std.posix.unexpectedErrno(err);
    }
}

//get terminal size
pub fn getTermSz() !TermSz {
    return if (builtin.os.tag == .windows) try getTermSzWin() else try getTermSzLinux();
}

pub fn initTermSize() !void {
    term_sz = try getTermSz();
}

It’s better in various ways to post code directly, rather than screenshots of it, FYI. We prefer that here.

2 Likes