¿Cómo llego anchura y la altura de mi terminal con ioctl?
Pregunta
¿Qué tengo que cambiar para hacer este trabajo?
#!/usr/bin/perl
use 5.012;
use warnings;
require "/usr/lib/perl5/vendor_perl/5.12.1/x86_64-linux-thread-multi/sys/ioctl.ph";
my ($rows, $cols, $xpix, $ypix);
my $winsize = "\0" x 8;
my $TIOCGWINSZ = 0x40087468; # should be require sys/ioctl.pl
if (ioctl(STDOUT, $TIOCGWINSZ, $winsize)) {
($rows, $cols, $xpix, $ypix) = unpack('S4', $winsize);
} else {
say "something didn't work" and exit;
}
Solución
Esto funciona muy bien para mí:
#!perl
use strict;
use warnings;
require 'sys/ioctl.ph';
my $winsize = ""; # Silence warning
if (ioctl(STDOUT, TIOCGWINSZ() , $winsize)) {
my ($rows, $cols, $xpix, $ypix) = unpack 'S4', $winsize;
print join ":", $rows, $cols, $xpix, $ypix;
print "\n";
} else {
warn "Something didn't work.\n";
}
El requieren no necesita (y no debería tener) la ruta completa; TIOCGWINSZ ya está definido por la carga de la cabecera ioctl, y no hay ninguna señal de que el escalar de destino tiene que ser inicializado al tamaño correcto (aunque si no está inicializado en absoluto, Perl lanza una advertencia, ya que no parece reconocer la read
especial la naturaleza -como de ioctl, así que me puse a "" sólo para calmar eso).
Otros consejos
Para obtener el número de filas y columnas, que estoy haciendo esto:
#!/usr/bin/perl
use strict;
use warnings;
my $cols = 80;
my $rows = 24;
for (`stty -a`) {
/columns ([0-9]+);/ and do { if ($1 > 0) { $cols = $1; }};
/rows ([0-9]+);/ and do { if ($1 > 0) { $rows = $1; }};
}
print "cols=$cols\trows=$rows\n";
¿Por qué no usar Term::Size
? Esto utiliza el método ioctl()
, envuelto en buen código XS ordenada todo listo para usar desde Perl.
Una forma de la otra que va a tener pedirle C para decirle lo que el valor de TIOCGWINSZ
es. Bien podría conseguir que le diga el tamaño del otro argumento, también, mientras estás en ello.
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <termios.h>
int
main(argc, argv)
int argc;
char *argv[];
{
struct winsize mywinsize;
int ttyfd;
if ((ttyfd = open("/dev/tty", O_RDWR|O_NOCTTY)) == -1) {
perror("open /dev/tty");
exit(-1);
}
if (ioctl(ttyfd, TIOCGWINSZ, &mywinsize) == -1) {
perror("ioctl TIOCGWINSZ");
exit(-1);
}
printf("TIOCGWINSZ %#08lx\n", TIOCGWINSZ );
printf("sizeof struct winsize %lu\n", sizeof(struct winsize) );
printf("rows %d\n", mywinsize.ws_row );
printf("cols %d\n", mywinsize.ws_col );
if (fclose(stdout) == EOF) {
perror("close stdout");
exit(-1);
}
exit(0);
}
Tal vez algún alma caritativa le puede mostrar cómo envolver que en Inline::C
para usted, pero mientras tanto, esto debería ser suficiente. Tenga en cuenta que este es un programa portable, ya que se ejecuta en ambos tipos de sistemas:
? ? BSD
OpenBSD% cc getwinsz.c && a.out
TIOCGWINSZ 0x40087468
sizeof struct winsize 8
rows 81
cols 166
Darwin% cc getwinsz.c && a.out
TIOCGWINSZ 0x40087468
sizeof struct winsize 8
rows 37
cols 126
? ? SysV
Slolaris% cc getwinsz.c && a.out
TIOCGWINSZ 0x005468
sizeof struct winsize 8
rows 37
cols 126
Leenooxe% cc getwinsz.c && a.out
TIOCGWINSZ 0x005413
sizeof struct winsize 8
rows 37
cols 126
Term::ReadKey
tiene incorporado un método para recuperar el tamaño de la terminal, y se es compatible con una gama de diferentes terminales incluyendo Windows. Teniendo en cuenta la gran número de módulos en CPAN que utilizan este módulo , es probable que ya tiene instalado.
#!/usr/bin/perl -w
use strict;
use Term::ReadKey qw/ GetTerminalSize /;
my @winsize = &GetTerminalSize(\*STDOUT);
my ($cols, $rows, $xpix, $ypix) = @winsize;
print "cols:$cols rows:$rows xpix:$xpix ypix:$ypix\n";