Perl Cd Bookshelf [Electronic resources] نسخه متنی

اینجــــا یک کتابخانه دیجیتالی است

با بیش از 100000 منبع الکترونیکی رایگان به زبان فارسی ، عربی و انگلیسی

Perl Cd Bookshelf [Electronic resources] - نسخه متنی

| نمايش فراداده ، افزودن یک نقد و بررسی
افزودن به کتابخانه شخصی
ارسال به دوستان
جستجو در متن کتاب
بیشتر
تنظیمات قلم

فونت

اندازه قلم

+ - پیش فرض

حالت نمایش

روز نیمروز شب
جستجو در لغت نامه
بیشتر
لیست موضوعات
توضیحات
افزودن یادداشت جدید

4.19. Program: words



Have you ever wondered how
programs like ls generate columns of sorted
output that you read down the columns instead of across the rows? For
example:

awk      cp       ed       login    mount    rmdir    sum
basename csh egrep ls mt sed sync
cat date fgrep mail mv sh tar
chgrp dd grep mkdir ps sort touch
chmod df kill mknod pwd stty vi
chown echo ln more rm su

Example 4-2 does this.

Example 4-2. words


  #!/usr/bin/perl -w
# words - gather lines, present in columns
use strict;
my ($item, $cols, $rows, $maxlen);
my ($xpixel, $ypixel, $mask, @data);
getwinsize( );
# first gather up every line of input,
# remembering the longest line length seen
$maxlen = 1;
while (<>) {
my $mylen;
s/\s+$//;
$maxlen = $mylen if (($mylen = length) > $maxlen);
push(@data, $_);
}
$maxlen += 1; # to make extra space
# determine boundaries of screen
$cols = int($cols / $maxlen) || 1;
$rows = int(($#data+$cols) / $cols);
# pre-create mask for faster computation
$mask = sprintf("%%-%ds ", $maxlen-1);
# subroutine to check whether at last item on line
sub EOL { ($item+1) % $cols = = 0 }
# now process each item, picking out proper piece for this position
for ($item = 0; $item < $rows * $cols; $item++) {
my $target = ($item % $cols) * $rows + int($item/$cols);
my $piece = sprintf($mask, $target < @data ? $data[$target] : ");
$piece =~ s/\s+$// if EOL( ); # don''t blank-pad to EOL
print $piece;
print "\n" if EOL( );
}
# finish up if needed
print "\n" if EOL( );
# not portable -- linux only
sub getwinsize {
my $winsize = "\0" x 8;
my $TIOCGWINSZ = 0x40087468;
if (ioctl(STDOUT, $TIOCGWINSZ, $winsize)) {
($rows, $cols, $xpixel, $ypixel) = unpack(''S4'', $winsize);
} else {
$cols = 80;
}
}

The most obvious way to print out a sorted list in columns is to
print each element of the list, one at a time, padded out to a
particular width. Then when you''re about to hit the end of the line,
generate a newline. But that only works if you''re planning on reading
each row from left to right. If you instead expect to read it down
each column, this approach won''t do.

The words program is a filter that generates
output going down the columns. It reads all input, keeping track of
the length of the longest line seen. Once everything has been read
in, it divides the screen width by the length of the longest input
record seen, yielding the expected number of columns.

Then the program goes into a loop that executes once per input
record, but the output order isn''t in the obvious order. Imagine you
had a list of nine items:

Wrong       Right
----- -----
1 2 3 1 4 7
4 5 6 2 5 8
7 8 9 3 6 9

The words program does the necessary
calculations to print out elements (1,4,7) on one
line, (2,5,8) on the next, and
(3,6,9) on the last.

To figure out the current window size, this program does an
ioctl call. This works fine—on the system it
was written for. On any other system, it won''t work. If that''s good
enough for you, then good for you. Recipe 12.17 shows how to find this on your system using
the ioctl.ph file, or with a C program. Recipe 15.4 shows a more portable solution, but that
requires installing a CPAN module.

4.19.1. See Also


Recipe 15.4

/ 875