كيف أحصل على عرض وارتفاع محطة بلدي مع IOCTL؟
سؤال
ماذا علي أن أتغير لجعل هذا العمل؟
#!/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;
}
مستوحاة من إجابة تشريست في من عمود إلى صف.
المحلول
هذا يعمل بشكل جيد بالنسبة لي:
#!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";
}
لا يحتاج المتطلبات (ولا ينبغي أن يكون) المسار الكامل ؛ تم تعريف Tiocgwinsz بالفعل عن طريق تحميل رأس IOCTL ، وليس هناك أي علامة على أنه يجب تهيئة قيود الوجهة إلى الحجم الصحيح (على الرغم من أنه إذا لم يتم تهيئته على الإطلاق ، فإن Perl يلقي تحذيرًا لأنه لا يبدو أنه يتعرف على الخاص read
-مثل طبيعة IOCTL ، لذلك قمت بتعيينها على "فقط لتهدئة ذلك).
نصائح أخرى
للحصول على عدد الصفوف والأعمدة ، أفعل هذا:
#!/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";
لماذا لا تستخدم فقط Term::Size
؟ هذا يستخدم ioctl()
الطريقة ، اختتمت في رمز XS أنيق جميل كل شيء جاهز للاستخدام من Perl.
إحدى طرق الأخرى التي ستطلب من C أن تخبرك بها ما هي قيمة TIOCGWINSZ
هو. قد تحصل عليه أيضًا لإخبارك بحجم الوسيطة الأخرى أيضًا ، أثناء وجودك فيه.
#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);
}
ربما توضح لك روح طيبة كيفية لف ذلك Inline::C
بالنسبة لك ، ولكن في الوقت نفسه ، يجب أن يكون هذا كافيا. لاحظ أن هذا برنامج محمول ، لأنه يعمل على أنواع الأنظمة ̲b̲o̲t̲h̲:
☺ 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
لديه طريقة مدمجة لاسترداد حجم المحطة ، وهي يدعم مجموعة من المحطات المختلفة بما في ذلك النوافذ. باعتبار ال عدد كبير من الوحدات النمطية على CPAN التي تستخدم هذه الوحدة, ، من المحتمل أن تكون قد تم تثبيته بالفعل.
#!/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";