Perl processor for Rubik's JTimer Drupal nodes

#!/usr/bin/perl -w
use strict;
=for docs

We have a few files full of JTimer data for
all solves performed so far.
They're in <code> blocks for Drupal formatting.
We ignore anything outside the code blocks.
We collect data fields from interesting lines and reformat them.
The collected data is added to a table and eventually outputted
in a tab delimited file for pasting into a nice spreadsheet.

=cut


use Date::Manip qw(Date_Init ParseDate UnixDate);
use File::Slurp;
use tmstub;
# this needs to be  called or Date::Manip won't work as expected on some platforms...
Date_Init("TZ=GB");
# read these files...
@ARGV = (
    "3x3x3-timelog-2008-10-11.txt",
    "3x3x3-timelog-2008-10-26.txt",
    "3x3x3-timelog-2008-11-01.txt",
);
my $outfile = "3x3x3-summary.txt";
# line counter, curent code block, and code block counter...
my($codeblock, $cbc) = (undef, 0);
# Results table (with heading row)...
my @results = ([qw(when average fastest slowest)]);
my($type, $when, $avg, $fast, $slow);
while (<>) {
    chomp; s/^\s+//; s/\s+$//;
    # entering a new code block...
    if(/^<code>$/){
        if(defined $codeblock){
            t "ERR: already in code block $codeblock at $. of $ARGV";
        }
        $codeblock = ($cbc++);
        next;
    }
    # leaving a code block...
    # this only works if the block contained everything we need!
    if(/^<\/code>$/){
        if(not defined $codeblock){
            t "ERR: not in a code block at $. of $ARGV";
        }
        # Results to list...
        push @results, [$when, $avg, $fast, $slow];
        undef $codeblock;
        next;
    }
    # heading line regex: captures session type and full date-time...
    if(/^----- Rubik's JTimer (Session Statistics|Best Average) for (.*) -----$/){
        ($type, $when) = ($1, $2);
        # process date and time  info...
        my $dm = ParseDate($when);
        my $epsec = UnixDate($dm,"%s");
        my $when = localtime($epsec);
        next;
    }
    if(/^Average:\s*(.*)$/){ $avg = proctime($1); next;}
    if(/^Fastest Time:\s*(.*)$/){ $fast = proctime($1); next; }
    if(/^Slowest Time:\s*(.*)$/){ $slow = proctime($1); next;}
} continue {
    # change of file
    t "file: $ARGV $. lines " if eof;
    close ARGV if eof;      # Not eof()!
}
t "sessions processed: ".( scalar(@results) - 1 );
# dump results to output file as tab separated fields...
open OUT, ">$outfile" or die "unable to open $outfile for writing:$!";
foreach(@results){
    print OUT join("\t", @$_)."\n";
}
close OUT;


# Times come along in the form: -
# minutes:seconds.hundredths
# if under a minute the minutes will be absent
# minutes are optional but seconds are not!
sub proctime {
    my $t = shift;
    return $t if ($t eq 'DNF');
    die "bad time '$t' at $ARGV $." unless $t =~ /^((\d+):)?(\d?\d)\.(\d\d)$/;
    my($min, $sec, $hund) = ($2, $3, $4);
    $min = 0 if not defined $min;
    return sprintf("%d:%02d.%02d",$min,$sec,$hund);
    #~ my $millis = ($min * 60 * 1000)
        #~ + ($sec * 1000)
        #~ + ($hund * 10);
    #~ return sprintf("%.02f", $millis/1000);
}