custom diagnostics in example test failure
[barcat.git] / barcat
diff --git a/barcat b/barcat
index 5ba6e74fee712183fa7578c55dd9ca8e080e51ad..63eb3a5fd2820f45ac14488962d66b408e44dc6f 100755 (executable)
--- a/barcat
+++ b/barcat
@@ -78,7 +78,7 @@ GetOptions(\%opt,
                exit;
        },
        'usage|h' => sub {
-               local $/;
+               local $/ = undef;  # slurp
                my $pod = readline *DATA;
                $pod =~ s/^=over\K/ 25/;  # indent options list
                $pod =~ s/^=item\ \N*\n\n\N*\n\K (?:(?:^=over.*?^=back\n)?(?!=)\N*\n)*/\n/g;
@@ -124,7 +124,7 @@ $opt{'signal-stat'} //= exists $SIG{INFO} ? 'INFO' : 'QUIT';
 $opt{markers} //= '=avg >31.73v <68.27v +50v |0';
 $opt{palette} //= $opt{color} && [31, 90, 32];
 $opt{hidemin} = ($opt{hidemin} || 1) - 1;
-$opt{input} = @ARGV && $ARGV[0] =~ m/\A[-0-9]/ ? \@ARGV : undef
+$opt{input} = (@ARGV && $ARGV[0] =~ m/\A[-0-9]/) ? \@ARGV : undef
        and undef $opt{interval};
 
 my (@lines, @values, @order);
@@ -152,15 +152,17 @@ my $valmatch = qr<
 while (defined ($_ = $opt{input} ? shift @{ $opt{input} } : readline)) {
        s/\r?\n\z//;
        s/\A\h*// unless $opt{unmodified};
-       push @values, s/$valmatch/\n/ && $1;
-       push @order, $1 if length $1;
-       if (defined $opt{trim} and defined $1) {
+       my $valnum = s/$valmatch/\n/ && $1;
+       push @values, $valnum;
+       push @order, $valnum if length $valnum;
+       if (defined $opt{trim} and defined $valnum) {
                my $trimpos = abs $opt{trim};
-               $trimpos -= length $1 if $opt{unmodified};
+               $trimpos -= length $valnum if $opt{unmodified};
                if ($trimpos <= 1) {
                        $_ = substr $_, 0, 2;
                }
                elsif (length > $trimpos) {
+                       # cut and replace (intentional lvalue for speed, contrary to PBP)
                        substr($_, $trimpos - 1) = '…';
                }
        }
@@ -184,7 +186,7 @@ sub color {
 sub sival {
        my $unit = int(log(abs $_[0] || 1) / log(10) - 3*($_[0] < 1) + 1e-15);
        my $float = $_[0] !~ /\A0*[-0-9]{1,3}\z/;
-       sprintf('%3.*f%1s',
+       return sprintf('%3.*f%1s',
                $float && ($unit % 3) == ($unit < 0),  # tenths
                $_[0] / 1000 ** int($unit/3),   # number
                $#{$opt{units}} * 1.5 < abs $unit ? "e$unit" : $opt{units}->[$unit/3]
@@ -208,7 +210,7 @@ my $lenval = $opt{'value-length'} // max map { length } @order;
 my $len    = defined $opt{trim} && $opt{trim} <= 0 ? -$opt{trim} + 1 :
        max map { length $values[$_] && length $lines[$_] }
                0 .. min $#lines, $opt{hidemax} || ();  # left padding
-my $size   = $range &&
+my $size   = defined $opt{width} && $range &&
        ($opt{width} - $lenval - $len) / $range;  # bar multiplication
 
 my @barmark;
@@ -220,13 +222,22 @@ if ($opt{markers} and $size > 0) {
                                return sum(@order) / @order;
                        }
                        elsif ($func =~ /\A([0-9.]+)v\z/) {
+                               die "Invalid marker $char: percentile $1 out of bounds\n" if $1 > 100;
                                my $index = $#order * $1 / 100;
                                return ($order[$index] + $order[$index + .5]) / 2;
                        }
-                       else {
+                       elsif ($func =~ /\A-?[0-9.]+\z/) {
                                return $func;
                        }
-               } - $minval;
+                       else {
+                               die "Unknown marker $char: $func\n";
+                       }
+               };
+               defined $pos or do {
+                       warn $@ if $@;
+                       next;
+               };
+               $pos -= $minval;
                $pos >= 0 or next;
                color(36) for $barmark[$pos * $size] = $char;
        }
@@ -265,7 +276,7 @@ while ($nr <= $#lines) {
        if ($opt{spark}) {
                say '' if $opt{width} and $nr and $nr % $opt{width} == 0;
                print color($color), $opt{spark}->[
-                       !$val ? 0 : # blank
+                       !$val || !$#{$opt{spark}} ? 0 : # blank
                        $val == $order[0] ? -1 : # max
                        $val == $order[-1] ? 1 : # min
                        $#{$opt{spark}} < 3 ? 1 :
@@ -289,6 +300,7 @@ continue {
 }
 say $opt{palette} ? color(0) : '' if $opt{spark};
 
+       return $nr;
 }
 
 sub show_stat {
@@ -309,6 +321,7 @@ sub show_stat {
                );
        }
        say '';
+       return 1;
 }
 
 sub show_exit {