如何在 Go 中获取终端大小。在 C 中,它看起来像这样:
struct ttysize ts;
ioctl(0, TIOCGWINSZ, &ts);
但是我如何在 Go 中访问 TIOCGWINSZ
cgo编译器目前无法处理ac函数中的变量参数和c头文件中的宏,所以不能做一个简单的
// #include <sys/ioctl.h>
// typedef struct ttysize ttysize;
import "C"
func GetWinSz() {
var ts C.ttysize;
C.ioctl(0,C.TIOCGWINSZ,&ts)
}
要绕过宏使用常量,所以
// #include <sys/ioctl.h>
// typedef struct ttysize ttysize;
import "C"
const TIOCGWINSZ C.ulong = 0x5413; // Value from Jed Smith's answer
func GetWinSz() {
var ts C.ttysize;
C.ioctl(0,TIOCGWINSZ,&ts)
}
然而,cgo 仍然会在 ioctl 的原型中对 ... 大喊大叫。您最好的选择是使用带有特定数量参数的 ac 函数包装 ioctl 并将其链接。作为黑客,您可以在上面的评论中执行此操作 import "C"
// #include <sys/ioctl.h>
// typedef struct ttysize ttysize;
// void myioctl(int i, unsigned long l, ttysize * t){ioctl(i,l,t);}
import "C"
const TIOCGWINSZ C.ulong = 0x5413; // Value from Jed Smith's answer
func GetWinSz() {
var ts C.ttysize;
C.myioctl(0,TIOCGWINSZ,&ts)
}
我没有对此进行测试,但类似的东西应该可以工作。
最好的方法是使用 syscall 包。syscall 包没有定义 ioctl 函数,因为它只是做了很多不同的事情,但您仍然可以这样调用它:
syscall.Syscall(syscall.SYS_IOCTL, uintptr(fd), uintptr(TIOCGWINSZ), uintptr(unsafe.Pointer(&ts)))
剩下的两件事是复制 winsize 结构和您需要的常量。用于此的工具是 godefs,它将通过查看 C 头文件中的结构和常量来生成一个 .go 源文件。创建一个如下所示的 termios.c 文件:
#include <termios.h>
enum {
$TIOCGWINSZ = TIOCGWINSZ
};
typedef winsize $winsize;
现在运行
godefs -gpackagename termios.c > termios.go
现在您应该拥有获得终端尺寸所需的一切。设置大小就像在 termios.c 中添加另一个常量一样简单。
const (
TIOCGWINSZ = 0x5413
TIOCGWINSZ_OSX = 1074295912
)
type window struct {
Row uint16
Col uint16
Xpixel uint16
Ypixel uint16
}
func terminalWidth() (int, error) {
w := new(window)
tio := syscall.TIOCGWINSZ
if runtime.GOOS == "darwin" {
tio = TIOCGWINSZ_OSX
}
res, _, err := syscall.Syscall(syscall.SYS_IOCTL,
uintptr(syscall.Stdin),
uintptr(tio),
uintptr(unsafe.Pointer(w)),
)
if int(res) == -1 {
return 0, err
}
return int(w.Col), nil
}
随便浏览一下文档,似乎还没有做太多的工作——事实上,我根本找不到ioctl
。
对于这样一种语言还处于起步阶段,可以肯定地说你是在人迹罕至的地方。TIOCGWINSZ
本身只是一个常量整数(我在 Linux 源代码中找到了它的值):
#define TIOCGWINSZ 0x5413
不过,祝你好运。