round partial sum to avoid floating point errors
[barcat.git] / barcat
diff --git a/barcat b/barcat
index 879624860a84d679ba05b82a65492d4c5795a576..0ab19d9c1159eb7349cf005cd52f0d6ebfc38e22 100755 (executable)
--- a/barcat
+++ b/barcat
@@ -81,7 +81,10 @@ GetOptions(\%opt,
                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;
+               $pod =~ s{
+                       ^=item \h \N*\n\n \N*\n \K  # first line
+                       (?: (?: ^=over .*? ^=back\n )? (?!=) \N*\n )*
+               }{\n}g;  # abbreviate options
                $pod =~ s/[.,](?=\n)//g;  # trailing punctuation
                $pod =~ s/^=item\ \K(?=--)/____/g;  # align long options
                # abbreviate <variable> indicators
@@ -210,7 +213,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;
@@ -222,13 +225,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;
        }
@@ -267,7 +279,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 :
@@ -296,7 +308,7 @@ say $opt{palette} ? color(0) : '' if $opt{spark};
 
 sub show_stat {
        if ($opt{hidemin} or $opt{hidemax}) {
-               printf '%s of ', sum(grep { length }
+               printf '%.8g of ', sum(grep { length }
                        @values[$opt{hidemin} .. ($opt{hidemax} || @lines) - 1]
                ) // 0;
        }
@@ -547,12 +559,12 @@ In PostgreSQL from within the client:
 
 Earthquakes worldwide magnitude 1+ in the last 24 hours:
 
-    https://earthquake.usgs.gov/earthquakes/feed/v1.0/summary/1.0_day.csv |
+    curl https://earthquake.usgs.gov/earthquakes/feed/v1.0/summary/1.0_day.csv |
     column -tns, | barcat -f4 -u -l80%
 
 External datasets, like movies per year:
 
-    curl https://github.com/prust/wikipedia-movie-data/raw/master/movies.json |
+    curl https://github.com/prust/wikipedia-movie-data/raw/master/movies.json -L |
     perl -054 -nlE 'say if s/^"year"://' | uniq -c | barcat
 
 But please get I<jq> to process JSON
@@ -560,7 +572,7 @@ and replace the manual selection by C<< jq '.[].year' >>.
 
 Pokémon height comparison:
 
-    curl https://github.com/Biuni/PokemonGO-Pokedex/raw/master/pokedex.json |
+    curl https://github.com/Biuni/PokemonGO-Pokedex/raw/master/pokedex.json -L |
     jq -r '.pokemon[] | [.height,.num,.name] | join(" ")' | barcat
 
 USD/EUR exchange rate from CSV provided by the ECB:
@@ -571,7 +583,7 @@ USD/EUR exchange rate from CSV provided by the ECB:
 
 Total population history in XML from the World Bank:
 
-    curl http://api.worldbank.org/v2/country/1W/indicator/SP.POP.TOTL |
+    curl http://api.worldbank.org/v2/country/1W/indicator/SP.POP.TOTL -L |
     xmllint --xpath '//*[local-name()="date" or local-name()="value"]' - |
     sed -r 's,</wb:value>,\n,g; s,(<[^>]+>)+, ,g' | barcat -f1 -H