# # progress_bar # # Input: $1 - A message to display with the progress bar. It can contain # any of the following special 3-character strings, each of which # will be converted to the following value: # # - the progress bar itself # - the current count #

- the percentage finished # - estimated remaining time # - the total count # # $2 - A total count # $3 - (optional) The 'done' symbol (default is '@') # $4 - (optional) The 'todo' symbol (default is '-') # # Output: A closure that takes a count, and updates the progress bar based # on its value. When the progress bar is done, it should be called # with no arguments, to show that the progress is complete -and- to # print a final newline. ## sub progress_bar { my ($msg, $total, $done_sym, $todo_sym) = @_; ($total || 0) or fatal("total can NOT be zero/undefined!"); $done_sym ||= '@'; $todo_sym ||= '-'; $| = 1; my $start = time(); my $last = $start; my $remain = "???"; my $b_left = ($msg =~ //)? 1: 0; my $c_prog = sub { my ($count) = @_; my $b_done = defined($count)? 0: 1; $b_done and $count = $total; ($count > $total) and $count = $total; my $pcnt = sprintf "%6.2f", 100.0 * $count / $total; my $new_msg = $msg; # Calculate estimated remaining time my $time = time(); my $dtime = $time - $start; if ($b_done) { $remain = "Finished"; } elsif ($b_left and $count and $dtime and $time - $last > 3) { $last = $time; my $rate = ($count / $dtime); my $nsec = int(($total - $count) / $rate); my $hr = my $min = 0; if ($nsec > 3600) { $hr = int($nsec / 3600); $nsec -= 3600 * $hr } if ($nsec > 60) { $min = int($nsec / 60); $nsec -= 60 * $min } if ($hr) { $remain = sprintf "%02d:%02d:%02d", $hr, $min, $nsec; } elsif ($min) { $remain = sprintf "%02d:%02d", $min, $nsec; } else { my $s = (1 == $nsec)? "": "s"; $remain = "$nsec second$s"; } } $new_msg =~ s//$count/g; $new_msg =~ s/

/$pcnt/g; $new_msg =~ s//$total/g; $new_msg =~ s//$remain/g; my $len = 79 + 3 - length($new_msg); my $ndone = int($len * $count / $total); my $ntodo = $len - $ndone; my $bar = ($done_sym x $ndone) . ($todo_sym x $ntodo); $new_msg =~ s//$bar/; print "$new_msg\r"; $b_done and print "\n"; }; return $c_prog; }