#!/usr/bin/perl -w
# mls - Fancy PERL version of the original mls, which was
# #alias mlsnoigc 'madr < ~/bin/madrls |& grep entry | sed s/".*file name: "// | sed s/FORTRAN// | awk -f ~/bin/madrfix.awk | sort -n | uniq'
# alias mlsnoigc 'madr < ~/bin/madrls | sed "s/^.*file name: //" | grep entry | awk -f ~/bin/madrfix.awk | sort -n | uniq'
# alias mls 'mlsnoigc | igc ".*\!*"'
# Unlike the original, it highlights definitions, knows when to supply
# empty slot info, and can take more than one pattern. Despite all this,
# it seems to be somewhat faster.
#
# Highlighting
# ------------
# Bold: File is readable, and madr will ask questions if you
# try to neg the definition.
# Cyan: File is a symbolic link.
# Yellow background: The definition is not the only one to reference that file!
# Partly inspired by Example 4.18 of The Perl Cookbook.
# Wish list:
#
# Make it more portable
# i.e. it does not work on cass because cass does not have
# Term::ANSIColor. I do not need it much on cass, but YMMV.
#
# Have a term width function that actually works!
# cgps03 (PERL 5.8.3, Fedora) does not have Term::ReadKey.
#
# mls -l anyone? i.e.:
# 1 NP11.MQ21 256 1 mJy/b 21h08m15.88s, 89d00'00.0"
# 9 IA1ADQQACI.MQ21 1024 1 mJy/b 21h08m15.88s, 63d34'22.2"
# 10 IA1QQA.V21CJ 960 1 mJy/b 21h08m15.88s, 63d34'22.2"
# 17 IA1AJQQACK.P21 1024 none 21h08m15.88s, 63d34'22.2"
#
# This should really take a format string (or even 2, for images and
# visibilities) to customize what is displayed.
# See DRAORed.pm's readdef().
#
# 4/26/2004: No longer needs write permission in the directory.
use strict;
use Term::ANSIColor qw(:constants);
#use DRAORed;
# Returns $dirna/$fn for the first $dirna in @dirposs for which $dirna/$fn
# would be writable. Dies if none is found.
sub writable {
my ($fn, @dirposs) = @_;
foreach my $dirna (@dirposs){
$dirna =~ s/^~/$ENV{HOME}/; # Sadly necessary
my $possres = "$dirna/$fn";
return $possres if(-w $dirna && (!(-e $possres) || -f $possres));
}
# Only gets here on failure.
die "$fn not writable in any of @dirposs";
}
# Returns a hash keyed by madr index of filenames (according to the madr
# definitions) matching any of the given list of madr patterns. The list
# of patterns defaults to ". _" if none is given.
sub hashna {
my @fnpatterns = @_;
my $verbose = 0;
if(@fnpatterns == 0){
@fnpatterns = (".", "_"); # Default pattern.
$verbose = 1;
}
# Use ./index.madrout if it is writable, otherwise ~/tmp/index.madrout if
# that will work, otherwise ~/index.madrout, otherwise die!
my $madroutput = writable("index.madrout", ".", "~/tmp", "~");
open(MADR, "|madr > $madroutput 2> /dev/null")
or die "Could not start |madr > $madroutput 2> /dev/null";
print MADR "name\n";
for my $mpat (@fnpatterns) {
print MADR "$mpat\n";
}
print MADR "\n";
print MADR "exit\n";
close(MADR);
my %mhash = ();
open(MADROUT, $madroutput) or die "Could not open $madroutput";
while () {
if (/ (\S+)\s*, entry: (\d+)/) {
$mhash{$2} = $1;
}
if($verbose){
if(/(\d+ +empty slots, \d+ +is first one)/){
my $info = $1;
chomp $info;
$info =~ s/\s+/ /g;
print "${info}.\n\n";
}
}
}
close(MADROUT) or die "Could not close $madroutput";
unlink($madroutput) or warn "Could not unlink $madroutput";
return \%mhash;
}
my $mnfns = hashna(@ARGV);
my %seen = ();
my (@indnums, @filnams);
my $maxlen = 1;
for my $key (sort {$a <=> $b} keys %{$mnfns}){
my $mylen = length($mnfns->{$key}) + 3;
if($mylen > $maxlen){
$maxlen = $mylen;
}
push(@indnums, $key);
push(@filnams, $mnfns->{$key});
++$seen{$mnfns->{$key}};
}
# determine boundaries of screen
my ($item, $cols, $rows);
my ($xpixel, $ypixel, $mask);
#($cols, $rows, $ypixel, $xpixel) = GetTerminalSize();
getwinsize();
$cols = int($cols / ($maxlen + 4)) || 1;
$rows = int(($#indnums + $cols) / $cols);
# pre-create mask for faster computation
$mask = sprintf("%%-%ds ", $maxlen - 3);
# Subroutine to check if at last item on line.
sub EOL { ($item + 1) % $cols == 0 }
## Check for duplicate definitions.
#my %hssdf = reverse %mnfns;
#my %mnfns2 = reverse %hssdf;
#print "There is a dupe!\n" if(%mnfns2 ne %mnfns);
# 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;
if($target < @indnums){
# Putting the column separation space into the number makes background
# coloring look better, but it requires testing for 1st columnness.
if($item % $cols){
$piece = sprintf("%5d ", $indnums[$target]);
}
else{
$piece = sprintf("%3d ", $indnums[$target]);
}
print $piece;
$piece = sprintf($mask, $filnams[$target]);
$piece =~ s/\s+$// if EOL(); # Don't blank-pad to EOL
print ON_YELLOW if($seen{$filnams[$target]} > 1);
print CYAN if(-l $filnams[$target]); # Apparently symbolic
print BOLD if(-r $filnams[$target]); # links are also plain files.
# Special check for madr families.
if($filnams[$target] =~ /(\w+)\.@@/){
print BOLD if(-f "${1}.01"); # At least it has its 1st member.
}
print $piece, RESET;
}
else{
print "";
}
print "\n" if EOL();
}
print "\n" if EOL(); # Finish up if needed.
# Not portable -- linux only (and not even Fedora! - RR), but it defaults
# to 80 columns.
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;
}
}