Как получить размер терминала в Go. В C это будет выглядеть так:
struct ttysize ts;
ioctl(0, TIOCGWINSZ, &ts);
Но как получить доступ к TIOCGWINSZ в Go
Как получить размер терминала в Go. В C это будет выглядеть так:
struct ttysize ts;
ioctl(0, TIOCGWINSZ, &ts);
Но как получить доступ к TIOCGWINSZ в Go
В настоящее время компилятор cgo не может обрабатывать переменные аргументы в функции c и макросы в заголовочных файлах 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 по-прежнему будет блевать на прототипе ... in ioctl. Лучше всего было бы обернуть ioctl функцией c, принимающей определенное количество аргументов, и связать ее. В качестве хака вы можете сделать это в комментарии выше 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, который генерирует исходный файл .go, просматривая структуры и константы в заголовках C. Создайте файл termios.c, который выглядит следующим образом:
#include <termios.h>
enum {
$TIOCGWINSZ = TIOCGWINSZ
};
typedef winsize $winsize;
Теперь беги
godefs -gpackagename termios.c > termios.go
Теперь у вас должно быть все необходимое для получения размера терминала. Установить размер так же просто, как добавить еще одну константу в termios.c.
читать: http://www.darkcoding.net/software/pretty-command-line-console-output-on-unix-in-python-and-go-lang/
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
Удачи, однако.