# Bck.pm - Library for incremental file-based backup
# (c) Martin Matousek, 30.08.2003 

package Bck;
use FileHandle;
use strict;
use warnings;

# ==============================================================================
sub PrintRecords
{
    my ( $Keys, $Records ) = @_;
    foreach ( @{$Keys} )
    {
        PrintRecord( $_, $Records->{$_} );
    }
}

sub PrintRecord
{
    my ( $key, $Record ) = @_;
    print sprintf( "%-45s %10d", Escape( $key ), $Record->[0] ) .
            " $Record->[1] " . sprintf( "%7d", $Record->[2] ) .
            " $Record->[3]\n";
}


# ==============================================================================
sub Read # \%Saved = ( \%Saved, file, ... )
# Reads old archive listing. Returns hash 
# Saved: filename->[ [mtime stat(a|c|d|o) size archive], ... ]
{
    my $Saved = shift;
    my $Record;
    my $FH = new FileHandle;
    my $Dir;

    foreach my $FileName ( @_ )
    {
        $FH->open( $FileName ) or die "bck: Cannot open file \"$FileName\"";
        $Dir = "";
        $FileName =~ /[^\/]+$/ and $Dir = $`;
        while( <$FH> )
        {
            /(\S+)\s+(\d+)\s*([acdo])\s+(\d+)\s+(\S+)\s*$/ or 
                die "bck: Listing error, $FileName:" .
                    $FH->input_line_number() . "\n";
            $Record = [ $2, $3, $4, $Dir .  $5 ];
            $_ = UnEscape( $1 );
            defined( $Saved->{ $_ } ) or $Saved->{ $_ } = [];
            push @{$Saved->{ $_ }}, $Record;
        }
        $FH->close();
    }
    return $Saved;
}

sub Flatten # (\%Saved)
{
    my $Saved = shift;
    foreach my $file ( keys( %{$Saved} ) )
    {
        $#{$Saved->{$file}} == 0 or die "Flatten only work with single listing";
        $Saved->{$file} =  $Saved->{$file}[0];
    }
}

sub Delete # ( \%Saved, \%ToDelete )
{
    my ($Saved, $ToDel ) = shift;
    my ($svdtm);

    foreach my $file ( keys( %{$ToDel} ) )
    {
        $svdtm = $Saved->{$file};
        defined( $svdtm ) and do {
            $svdtm = $svdtm->[0];
            inner: for( my $n = 0; $n <= $#{$ToDel->{$file}}; ++ $n )
            {
                $svdtm == $ToDel->{$file}[$n][0] and do {
                    splice @{$ToDel->{$file}}, $n, 1;
                    $#{$ToDel->{$file}} == 0 and delete( $ToDel->{$file} );
                    delete( $Saved->{$file} );
                    last inner;
                };
            }
       };
    }
}

sub Escape
{
    local $_;
    $_ = $_[0];
    s/([\001-\040\\])/sprintf( "\\x%.2lx", ord($1) )/ge;
    return $_;
}

sub UnEscape
{
    local $_;
    $_ = $_[0];
    s/\\-/-/g;
    s/\\n/\n/g;
    s/\\\"/\"/g;
    s/\\\'/\'/g;
    s/\\x(..)/chr( hex( $1 ) )/ge;
    return $_;
}

1;
