# (c) 2005-2007 Electronic Arts Inc.
# 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, aligned to 32768
# 2.30 FB Show Sectors

# 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
#
# cdu - cd disc usage
#
# SUMMARY
#
# cdu -options [file]
#     -<n>      limit to specified directory level depth
#     [files]   specify a file to get size of
#
# DESCRIPTION
#
# cdu recurses thru the specified directory tree, displaying
# the size of each folder, with sizes padded to 32k (ECC)
#
# RETURNS
#
# total size in MB
#
# SEE ALSO
#
# du, dir
#
# SAMPLE OUTPUT
#
# D:\packages\Util\1.6.5>cdu
#         Size      MB  Sectors  Files  Dirs Pathname
#      5898240     5.6     2880     29     0 bin
#      7929856     7.6     3872      2     0 build
#       557056     0.5      272      4     0 doc
#        32768     0.0       16      1     0 examples
#        32768     0.0       16      1     0 scripts
#      8585216     8.2     4192    184     0 source/cmn
#            0     0.0        0      0     1 source
#        65536     0.1       32      2     6 .
#     23101440    22.0    11280    223     8 . TOTAL
#
# END ABSTRACT
#


use strict;
use warnings;

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

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

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

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

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

	if (-f "$directory") {
		$subfilesize = -s "$directory";
		$filecount = 1;
		$dircount = 0;
		$totaldircount = 0;
		printf ('%12.0f%8.1f%9.0f%7d%6d', $subfilesize, ($subfilesize)/1048576, ($subfilesize)/2048, $filecount, $dircount);
		printf (" $directory\n");
	}
	else {
		opendir(D, $directory) || die;
		foreach(readdir D) {
			if (-f "$directory/$_") {
				$filecount += 1;
				my $thisfilesize = -s "$directory/$_";
				my $alignedsize = ($thisfilesize+32767)&~32767;
				$filesize += $alignedsize;
			}
			elsif (-d "$directory/$_" and "$_" ne "." and "$_" ne "..") {
				$dircount += 1;
				my $dirsize = GetDirSize("$directory/$_");
				$subfilesize += $dirsize;
			}
		}
		closedir(D);

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

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

	return $totalfilesize;
}

my $dirname = ".";
if (@ARGV == 1) {
	$dirname = shift @ARGV;
	if ($dirname eq "?") {
		PrintUsageAndExit();
	}
}

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

	my $totalsize = GetDirSize($dirname);

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

