#!/usr/bin/perl -w
#
# $Revision: 1.2 $ $Date: 2012-07-26 17:11:48-04 $
# $Source: /home/vogelke/bin/RCS/newfiles,v $
# $Host: sys7.com $
# $UUID: 6f70997b-9efb-34a4-9e7b-31e7f0060929 $
#
#<newfiles: shows list of recently-added directories and files.
#
# Examines lists of original and new files generated by find,
# prints separate lists of added directories and files.
#
# Usage: newfiles ORIGINAL NEW ADD
#
# Example:
#     % find ./program -print | sort > /tmp/ORIG
#     [do configure, build, etc.]
#     % find ./program -print | sort > /tmp/NEW
#     % newfiles /tmp/ORIG /tmp/NEW /tmp/ADD
#
# /tmp/ADD.d holds new directories, /tmp/ADD.f holds new files.

use Fcntl ':mode';
use subs qw/filetype/;
use strict;

my $forig = shift(@ARGV) || die "no original filelist";
my $fnew  = shift(@ARGV) || die "no new filelist";
my $tpl   = shift(@ARGV) || die "no template";

# Read the original list of files.
my %aorig;
my ($dfh, $fh);

open($fh, "< $forig") || die "$forig: can't read: $!\n";
while (<$fh>) {
    chomp;
    $aorig{$_} = 1;
}
close($fh);

# Read the new list of files, and find what's been added.
my %added;
open($fh, "< $fnew") || die "$fnew: can't read: $!\n";
while (<$fh>) {
    chomp;
    $added{$_} = 1 unless defined($aorig{$_});
}
close($fh);

# Divide added files into directories and anything else.
#
# Use reverse sort so we can just pipe the directories into
# "xargs rmdir" without trying to remove a parent directory
# before removing its children.

my $dlist = "$tpl.d";
my $rlist = "$tpl.f";
my $mode;
my $ft;

open($dfh, "> $dlist") || die "$dlist: can't write: $!\n";
open($fh,  "> $rlist") || die "$rlist: can't write: $!\n";

foreach (reverse sort keys %added) {
    ($mode) = (lstat($_))[2];
    next unless $mode;
    $ft = filetype($mode);

    if ($ft eq 'd') { print $dfh "$_\n"; }
    else            { print $fh  "$_\n"; }
}

close($dfh);
close($fh);
exit(0);

#---------------------------------------------------------------------
sub filetype {
    my ($mode) = @_;

    return '-' unless $mode;    # just in case stat failed

    S_ISBLK($mode)  && return 'b';
    S_ISDIR($mode)  && return 'd';
    S_ISFIFO($mode) && return 'p';
    S_ISLNK($mode)  && return 'l';
    S_ISREG($mode)  && return 'f';
    S_ISSOCK($mode) && return 's';
    S_ISCHR($mode)  && return 'c';

    return 'u';
}
