#!/usr/bin/perl

# watchdir:
# This script prints info about changes to the directory specified
# as a command-line argument. If no command-line arg is supplied,
# it watches the current directory.
# Cameron Hayne (macdev@hayne.net)  December 2005

use strict;
use warnings;

# global variables
my $interval = 10;    # time (in seconds) between checks

# If no command-line argument, use the current directory
my $dirname = scalar(@ARGV) >= 1 ? $ARGV[0]: ".";
die "$dirname is not a directory\n" unless -d $dirname;

sub get_dir_entries($)
{
    my ($dirname) = @_;

    my %entries = ();
    opendir(DIR, $dirname) or die "can't opendir $dirname: $!\n";
    while (defined(my $filename = readdir(DIR)))
    {
        next if $filename =~ /^\.\.?$/;     # skip . and ..
        $entries{$filename} = 1;
    }
    closedir(DIR);

    return \%entries;
}

sub diff_hash_keys($$)
{
    my ($ref_hashA, $ref_hashB) = @_;

    my %hashA = %$ref_hashA;
    my %hashB = %$ref_hashB;
    my @A_not_B = ();
    my @B_not_A = ();

    foreach (keys %hashA)
    {
        push(@A_not_B, $_) unless exists $hashB{$_};
    }
    foreach (keys %hashB)
    {
        push(@B_not_A, $_) unless exists $hashA{$_};
    }

    return (\@A_not_B, \@B_not_A);
}

MAIN
{
    $| = 1; # enable autoflushing of output so this works better when piped
    my $prev = undef;
    while (1)
    {
        my $date = localtime();
        my $curr = get_dir_entries($dirname);
        if (defined($prev))
        {
            my ($added, $removed) = diff_hash_keys($curr, $prev);
            foreach (sort @$added)
            {
                print "$date: Added file $_\n";
            }
            foreach (sort @$removed)
            {
                print "$date: Removed file $_\n";
            }
            if (@$added || @$removed)
            {
                print "\a"; # make a beep
            }
        }
        $prev = $curr;

        sleep $interval;
    }
}

