问题
What do I have to change to make this work?
#!/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;
}
Inspired by tchrist's answer in From column to row.
回答1:
This works just fine for me:
#!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";
}
The require doesn't need (and shouldn't have) the full path; TIOCGWINSZ is already defined by loading the ioctl header, and there's no sign that the destination scalar has to be initialized to the right size (although if it's not initialized at all, perl throws a warning because it doesn't seem to recognize the special read
-like nature of ioctl, so I set it to "" just to quiet that).
回答2:
To get the number of rows and columns, i'm doing this :
#!/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";
回答3:
Why not just use Term::Size? This uses the ioctl()
method, wrapped up in nice neat XS code all ready to use from Perl.
回答4:
One way of the other you’re going to have ask C to tell you what the value of TIOCGWINSZ
is. Might as well get it to tell you the size of the other argument, too, while you’re at it.
#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);
}
Perhaps some kind soul might show you how to wrap that in Inline::C
for you, but meanwhile, this should suffice. Note that this is a portable program, because it runs on ̲b̲o̲t̲h̲ kinds of systems:
☺ 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
回答5:
Term::ReadKey has a built-in method for retrieving the size of the terminal, and it supports a range of different terminals including Windows. Considering the sheer number of modules on CPAN that use this module, you likely already have this installed.
#!/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";
来源:https://stackoverflow.com/questions/4286158/how-do-i-get-width-and-height-of-my-terminal-with-ioctl