#!/usr/bin/perl -w
# (C) 2003-2007 Willem Jan Hengeveld <itsme@xs4all.nl>
# Web: http://www.xs4all.nl/~itsme/
#      http://wiki.xda-developers.com/
#
# $Id$
#

use strict;
use Getopt::Long;
use Cwd;
my %monthnames=(Jan=>1, Feb=>2, Mar=>3, Apr=>4, May=>5, Jun=>6, Jul=>7, Aug=>8, Sep=>9, Oct=>10, Nov=>11, Dec=>12);
# processes output of 'dir /s' and converts it to easily greppable
# lines with data, size, fullpath

# and of ls --full-time -lR    ( gnu ls )
# and of ls -lTaR              ( osx ls )

my $relative_to_cwd;
my $dotdrive='z';
sub usage {
return <<__EOF__
Usage: dir ... | updatedb [-c]
   -c       : relative to current dir
   -s DRV   : substitute driveletter for './'
__EOF__
}
GetOptions(
    "c"=>\$relative_to_cwd,
    "s=s" => \$dotdrive,
) or die usage();


my $basedir="";
my @base;
if ($relative_to_cwd) {
    $basedir= getcwd;
    @base= split /\\/, $basedir;
}
if (!@ARGV) {
    processfile("-")
}
else {
    for my $filename (@ARGV) {
        processfile($filename)
    }
}
sub getrelative {
    my ($curdir, $basedir)= @_;
    if (lc($curdir) eq lc($basedir)) {
        return "";
    }
    elsif (lc(substr($curdir, 0, length($basedir)+1)) eq lc($basedir."\\")) {
        return substr($curdir, length($basedir)+1);
    }
    else {
        my @cur= split /\\/, $curdir;
        my $i=0;
        while ($i<@base && $i<@cur && lc($base[$i]) eq lc($cur[$i])) {
            $i++;
        }
        return "..\\" x ( @base-$i ) . join("\\", @cur[$i..$#cur]);
    }
}

sub processfile {
    my $filename= shift;

    my $pathsep= "/";
    $basedir =~ s{[\\/]}{$pathsep}g;

    if ($filename eq "-") {
        *FH=*STDIN;
    }
    else {
        open FH, "<", $filename or die "$filename: $!\n";
    }

    # initialize to '.' for ls -lR output
    my $curdir= "$dotdrive:";
    while (<FH>) {
        s/\s+$//;
        if (/^ Directory of (.*)$/) {
            # dir header of windows dir listing
            (my $dirname=$1) =~ s{[\\/]$}{};
            $dirname =~ s{[\\/]}{$pathsep}g;
            $curdir= $relative_to_cwd ? getrelative($dirname, $basedir) : $dirname;
        }
        elsif (/^(.*):$/) {
            # dir header in ls-lr listing
            (my $dirname=$1) =~ s{[\\/]$}{};
            $dirname =~ s{[\\/]}{$pathsep}g;
            $curdir= $relative_to_cwd ? getrelative($dirname, $basedir) : $dirname;
            $curdir =~ s/^\.\//$dotdrive:\//;
        }
        elsif (/^([-dl])(?:[rsS-][w-][x-]){3}\s\d+\s+(\d+)\s+(\S+\s+\S+):\d\d\.\d+\s\S+\s(\S.*?)\/?$/) {
#  -rw-r--r-- 0     21401 2007-11-07 09:02:58.000000000 +0100 .bash_history
            my ($type, $size, $datetime, $filename)= ($1, $2, $3, $4);
            next if ($filename eq "." || $filename eq "..");

            if ($type eq "d") {
                printf("%-16s             %s%s%s%s\n", $datetime, $curdir, $pathsep, $filename, $pathsep);
            }
            elsif ($type eq "-") {
                printf("%-16s %11d %s%s%s\n", $datetime, $size, $curdir, $pathsep, $filename);
            }
        }
        elsif (/^([d-])(?:[rsS-][w-][x-]){3}\s+\d+\s\w+\s+\w+\s+(\d+)\s([A-Z][a-z][a-z])\s+(\d+)\s+(\S+)\s+(\d+)\s(\S.*)\/?$/) {
# -rw-r--r--     1 itsme  itsme       9336 Feb 28 12:00:53 2008 x.old
            my ($type, $size, $mon, $day, $time, $year, $filename)= ($1, $2, $3, $4, $5, $6, $7);
            next if ($filename eq "." || $filename eq "..");
            my $datetime= sprintf("%04d-%02d-%02d %s", $year, $monthnames{$mon}, $day, $time);
            if ($type eq "d") {
                printf("%-16s             %s%s%s%s\n", $datetime, $curdir, $pathsep, $filename, $pathsep);
            }
            elsif ($type eq "-") {
                printf("%-16s %11d %s%s%s\n", $datetime, $size, $curdir, $pathsep, $filename);
            }
        }
	elsif (/^([d-])(?:[rsS-][w-][x-]){3}\s+\d+\s+\w+\s+\w+\s+(\d+)\s(\w\w\w\s.\d\s.\d.\d\d)\s(.*)/) {
# drwxrwxr-x   2 0          3               96 Sep 14  2007 dist
            my ($type, $size, $datestr, $filename)= ($1, $2, $3, $4);
            next if ($filename eq "." || $filename eq "..");
	    my $datetime;
	    if ($datestr =~ /^(\w\w\w)\s+(\d+)\s+(\d+)$/) {
		    my ($mon, $day, $year)= ($1,$2,$3);
		    $datetime= sprintf("%04d-%02d-%02d ??:??", $year, $monthnames{$mon}, $day);
	    }
	    elsif ($datestr =~ /^(\w\w\w)\s+(\d+)\s+(\d+:\d+)$/) {
		    my ($mon, $day, $hhmm)= ($1,$2,$3);
		    my @t=localtime time();
		    my $year= $t[5]+1900;
		    $datetime= sprintf("%04d-%02d-%02d %s", $year, $monthnames{$mon}, $day, $hhmm);
	    }
            if ($type eq "d") {
                printf("%-16s             %s%s%s%s\n", $datetime, $curdir, $pathsep, $filename, $pathsep);
            }
            elsif ($type eq "-") {
                printf("%-16s %11d %s%s%s\n", $datetime, $size, $curdir, $pathsep, $filename);
            }

	}
        elsif (/^(\S+\s+\S+(?:\s\w\w)?)\s+<DIR>\s+(\S.*)$/) {
            # dir entry
            my ($thisdatetime, $thisdirname)= ($1, $2);
            next if ($thisdirname eq "." || $thisdirname eq "..");
            $thisdatetime= convertToYmd($thisdatetime);
            printf("%-16s             %s%s%s\\\n", $thisdatetime, $curdir, $pathsep, $thisdirname);
        }
        elsif (/^(\S+\s+\S+(?:\s\w\w)?)\s+([0-9,]+)\s(\S.*)$/) {
            # file entry
            my ($datetime, $size, $filename)= ($1, $2, $3);
            $size =~ s/[ ,]//g;

            $datetime= convertToYmd($datetime);

            printf("%-16s %11d %s%s%s\n", $datetime, $size, $curdir, $pathsep, $filename);
        }
        elsif (/^$/
            || /^\s+[0-9,]+\s+File\(s\)\s+[0-9,]+\s+bytes$/
            || /^ Volume in drive \w /
            || /^ Volume Serial Number is /
            || /^\s+Total Files Listed:/
            || /^total\s\d+/
            || /^\s+[0-9,]+\s+Dir\(s\)\s+[0-9,]+\s+bytes free/) {
            # ignore
        }
        else {
            #print "unknown line $_\n";
        }
    }
    close FH;
}

sub convertToYmd {
    my $mdyhm= shift;
    if ($mdyhm =~ m{(\d+)/(\d+)/(\d{4})\s+(\d+):(\d+)([ap])}) {
        my ($m, $d, $y, $hh, $mm, $ampm)= ($1,$2,$3,$4,$5,$6);
        if ($ampm eq "p" && $hh!=12 ) {
            $hh += 12;
        }
        elsif ($ampm eq "a" && $hh eq "12") {
            $hh= 0;
        }
        return sprintf("%04d-%02d-%02d %02d:%02d", $y, $m, $d, $hh, $mm);
    }
    else {
        # probably yyyy-mm-dd  hh:mm
        $mdyhm =~ s/\s+/ /g;
        return $mdyhm;
    }
}

