# (c) 2005-2006 Criterion Software Limited and its licensors. All Rights Reserved
# 1.22 BG DOS based Directory Usage.
# 2.00 FB Rewritten in Perl 
# 2.10 FB Align to 2048
# 2.20 FB Return size in MB 
# 2.30 FB Show Sectors 
# 2.40 FB -1 to only show one level deep
# 2.41 FB fix alignment using 2047 not 2048
# 2.42 FB -0 for no levels
# 2.43 FB sectors removed.  Take size / 2048 to get that

# This utility written for improving loadtimes, by Frank Barchard.  2004.6.28
# Its useful to get a directory listing of your DVD for a few reasons
# -Look for folders that contain few files, or are small in size, ane make them into big files.
# -Classify folders as Movies, Ingame, Boot, FE, BE and layout in that order (BE on outside) 

# Original version written in DOS by Brad Gour.
# Required minor updates for large files, and added File & Directory counts

#
# ABSTRACT
#
# du - disc usage
#
# SUMMARY
#
# du -options [file]
#     -<n>      limit to specified directory level depth
#     [files]   specify a file to get size of
#
# DESCRIPTION
#
# du recurses thru the specified directory tree, displaying
# the size of each folder
#
# RETURNS
#
# total size in MB
#
# SEE ALSO
#
# cdu, dir
#
# SAMPLE OUTPUT
#
# D:\packages\Util\1.7.1>du
#         Size      MB  Files  Dirs Pathname
#      5525690     5.3     29     0 bin
#      7903242     7.5      2     0 build
#       475274     0.5      4     0 doc
#          384     0.0      1     0 examples
#          465     0.0      1     0 scripts
#      4008752     3.8    184     0 source/cmn
#            0     0.0      0     1 source
#          523     0.0      2     6 .
#     17914330    17.1    223     8 . TOTAL
#
# END ABSTRACT
#


use strict;
use warnings;

#--- usage information
sub PrintUsageAndExit()
{
	print STDERR "DU (Disk Usage) - Version 2.42, by Brad Gour and Frank Barchard, EAC\n";
	print STDERR "USAGE: DU <folder>\n";
	exit 1;
}

my $totaldircount = 1;
my $totalfilecount = 0;
my $totalsectors = 0;

#------------------------------------------------------------------------------
# List all directories in a tree.
#------------------------------------------------------------------------------

sub GetDirSize($$$);

sub GetDirSize($$$)
{
	my ($directory, $optlevels, $level) = @_;
	my $totalfilesize = 0;

	my $dircount = 0;
	my $filecount = 0;
	my $filesize = 0;
	my $afilesize = 0;
	my $subfilesize = 0;

	opendir(D, $directory) || die;
	foreach(readdir D) {
		if (-f "$directory/$_") {
			$filecount += 1;
			my $thisfilesize = -s "$directory/$_";
			my $alignedsize = ($thisfilesize+2047)&~2047;
			$filesize += $thisfilesize;
			$afilesize += $alignedsize;
		}
		elsif (-d "$directory/$_" and "$_" ne "." and "$_" ne "..") {
			$dircount += 1;
			my $dirsize = GetDirSize("$directory/$_", $optlevels, $level+1);
			$subfilesize += $dirsize;
		}
	}
	closedir(D);

	$totaldircount += $dircount;
	$totalfilecount += $filecount;
	$subfilesize += $filesize;
	$totalfilesize += $subfilesize;
	$totalsectors += $afilesize;

	if ($level <= $optlevels) {
		printf ('%12.0f%8.1f%7d%6d', $filesize, ($filesize)/1048576, $filecount, $dircount);
		$directory =~ s/\.\///;
		printf (" $directory\n");
	}

	return $totalfilesize;
}

my $dirname = ".";
my $optlevels = 256;


if (@ARGV == 1) {
	my $arg = shift @ARGV;
	if ($arg eq "?") {
		PrintUsageAndExit();
	}
	elsif ($arg eq "-0") {
		$optlevels = 0;
	}
	elsif ($arg eq "-1") {
		$optlevels = 1;
	}
	elsif ($arg eq "-2") {
		$optlevels = 2;
	}
	elsif ($arg eq "-3") {
		$optlevels = 3;
	}
	elsif ($arg eq "-4") {
		$optlevels = 4;
	}
	else {
		$dirname = $arg;
	}
}

if (-f "$dirname") {
	my $subfilesize = -s "$dirname";
	printf ('%12.0f', $subfilesize);
	printf (" $dirname\n");
	exit (($subfilesize+1048575)/1048576);
}
else {
	printf ("        Size      MB  Files  Dirs Pathname\n");

	my $totalsize = GetDirSize($dirname, $optlevels, 0);

	printf ('%12.0f%8.1f%7d%6d', $totalsize, ($totalsize)/1048576, $totalfilecount, $totaldircount);
	printf (" $dirname TOTAL\n");
	exit (($totalsize+1048575)/1048576);
}

