#!/Perl
# NAME: dvdburn.pl, Version: 0.0.2
# AIM: Scan a directory, and suggest DVD write
# limits ... fill DVD to below ORANGE(warn) level
# by skipping FOLDER that put it OVER this limit.
# Present limit = 4.7GB DVD assumed, so
# LIMIT set to 4.5GB ... sort per FOLDER size
# add oldest/youngest columns # adjust to sector sizing
# Three examples
# 2010/04/17 - point out indivual files GREATER THAN ONE DVD SIZE
# 2010/01/14  - Minor adjustments
# Original: 22/07/2008 dirg3.pl for 700MB, but now changed to dvdsizes.pl...
# 30/10/2009 geoff mclane http://geoffair.net/mperl
use strict;
use warnings;
use Cwd;
use File::stat;
use File::Find;   # see http://perldoc.perl.org/File/Find.html
use Data::Dumper;
unshift(@INC, "C:\\GTools\\perl");
require 'logfile.pl' or die "Unable to load logfile.pl ...\n";
# log file stuff
my ($LF);
my $pgmname = $0;
if ($pgmname =~ /\w{1}:\\.*/) {
   my @tmpsp = split(/\\/,$pgmname);
   $pgmname = $tmpsp[-1];
}
my $perl_root = "C:\\GTools\\perl";
my $outfile = $perl_root."\\temp.$pgmname.txt";
open_log($outfile);

# FEATURES
my $add_def_if_none = 0;
my $def_file = "C:\\DTEMP";	# DEFAULT, if NO command input
#my $def_file = $perl_root;	# DEFAULT, if NO command input
my $recursive = 1;
my $block = 2048;	# was 512;
my $max_cd = 4.5 * 1024 * 1024 * 1024; # set at 4.5GB
my $load_log = 0;
my $verbose = 0;  # verbosity level
my $dbg_on = 0;
my $use_old_way = 0;
my $sort_per_size = 1;
my $sort_alpha = 0;
my $sort_decending = 0;    # largest FIRST, else smallest first
my $give_sprtf_a_go = 0;   # seems L, ll, even I64u, etc all FAIL in WIN32
# Used in sub get_aligned_size_stg($) {
my $fl_minn = 16;
my $ks_mink = 8;
my $min_file_len = 64;
my $msg_sub_add = "     ";
my $fill_each_dvd = 1;

# PROGRAM VARIABLES
my @warnings = ();
my @in_files = ();
my $out_count = 0;
my $max_count = 98;
my $last_time = 0;
my %exclude_dirs2 = ( 'scenery' => 1 );
my %exclude_dirs3 = ( 'FG' => 1 );
my %exclude_dirs = ();
my $got_exclude_dirs = 0;
my $got_exclude_root = 0;

# debug
my $dbg_01 = 0;

# FORWARD REFS
sub process_dir_array_ref($$$);

sub VERB1() { return ($verbose >= 1) }
sub VERB2() { return ($verbose >= 2) }
sub VERB3() { return ($verbose >= 3) }
# ...
sub VERB5() { return ($verbose >= 5) }
# ...
sub VERB9() { return ($verbose >= 9) }

sub prtw($) {
   my ($msg) = @_;
   prt($msg);
   $msg =~ s/\n$//;
   push(@warnings,$msg);
}

sub show_warnings() {
   if (@warnings) {
      prt( "Got ".scalar @warnings." WARNINGS...\n" );
      foreach my $msg (@warnings) {
         prt( "$msg\n" );
      }
   } else {
      prt( "No warnings issued.\n" ) if (VERB9());
   }
}

sub pgm_exit($$) {
   my ($val,$msg) = @_;
   show_warnings();
   if (length($msg)) {
      $msg .= "\n" if ( !($msg =~ /\n$/) );
      prt($msg); # if (($val > 0) || VERB9());
   }
   close_log($outfile,$load_log);
   exit($val);
}

sub prtv1($) {
   if (VERB1()) {
      prt(shift);
   }
}

sub prtso($) { print shift; }

sub prtsot($) {
   my $txt = shift;
   my $ct = time();
   if ($ct > $last_time) {
      $last_time = $ct;
      prtso($txt);
      $out_count++;
      if ($out_count > $max_count) {
         $out_count = 0;
         prtso("\n");
      }
   }
   #print shift;
   #$out_count++;
   #if ($out_count > $max_count) {
   #   $out_count = 0;
   #   #print "\n";
   #}
}

sub strip_dbl_quotes($) {
	my ($ln) = shift;
	if ($ln =~ /^".*"$/) {
		$ln = substr($ln,1,length($ln)-2);
	}
	return $ln;
}

##################################################
# My particular 'nice number'
sub get_nn($) { # perl nice number nicenum add commas
	my ($n) = shift;
	if (length($n) > 3) {
		my $mod = length($n) % 3;
		my $ret = (($mod > 0) ? substr( $n, 0, $mod ) : '');
		my $mx = int( length($n) / 3 );
		for (my $i = 0; $i < $mx; $i++ ) {
			if (($mod == 0) && ($i == 0)) {
				$ret .= substr( $n, ($mod+(3*$i)), 3 );
			} else {
				$ret .= ',' . substr( $n, ($mod+(3*$i)), 3 );
			}
		}
		return $ret;
	}
	return $n;
}

sub b2ks2($) {
   my ($d) = @_;
	my $oss;
	my $kss;
	my $lg = 0;
	my $ks = ($d / 1024); #// get Ks
	my $div = 1;
   if( $ks < 1024 ) {
      $div = 1;
      $oss = "KB";
   } elsif ( $ks < (1024*1024) ) {
	  $div = 1024;
      $oss = "MB";
   } elsif ( $ks < (1024*1024*1024) ) {
      $div = 1024 * 1024;
      $oss = "GB";
   } else {
      $div = 1024 * 1204 * 1240;
      $oss = "TB";
   }
   $kss = $ks / $div;
   $kss += 0.05;
   $kss *= 10;
   $lg = int($kss);
   $kss = $lg / 10;
   $kss .= '.0' if (!($kss =~ /\./));
   ###return( ($lg / 10) . " " . $oss );
   return "$kss$oss";
}

sub b2ks2_ok($) {
   my ($d) = @_;
	my $oss;
	my $kss;
	my $lg = 0;
	my $ks = ($d / 1024); #// get Ks
	my $div = 1;
   if( $ks < 1024 ) {
      $div = 1;
      $oss = "KB";
   } elsif ( $ks < (1024*1024) ) {
	  $div = 1024;
      $oss = "MB";
   } elsif ( $ks < (1024*1024*1024) ) {
      $div = 1024 * 1024;
      $oss = "GB";
   } else {
      $div = 1024 * 1204 * 1240;
      $oss = "TB";
   }
   $kss = $ks / $div;
   $kss += 0.05;
   $kss *= 10;
   $lg = int($kss);
   ###return( ($lg / 10) . " " . $oss );
   return( ($lg / 10) . $oss );
}


sub find_local_files_2($) {
   my ($dirs) = @_;
   my %file_list = ();
   my $last_dir = '';
   # $File::Find::dir  - is the current directory name, 
   # $_                - is the current filename within that directory 
   # $File::Find::name - is the complete pathname to the file.
   # eg
   # $File::Find::dir  = /some/path/
   # $_                = foo.ext
   # $File::Find::name = /some/path/foo.ext
   local *wanted_files = sub {
       my $f = $_;
       my $file = $File::Find::name;
       my $dir  = $File::Find::dir;
       my ($sb,$type);
       if (-d $file) {
         $type = 'DIR';
         if ($dir ne $last_dir) {
            $last_dir = $dir;
            prtsot(".");
         }
       } else {
          $type = 'FIL';
       }
       #return if (-d $f);
       #return if -l;
       if ($sb = stat($file)) {
          push (@{$file_list{$dir}{$type}}, [$file, $sb->size, $sb->mtime]);
       } else {
          prtw("WARNING: failed to 'stat' [$file]\n");
       }
   };

   File::Find::find(\&wanted_files, @{$dirs});
   return %file_list;
}

sub mycmp_decend {
	return -1 if (${$a}[0] < ${$b}[0]);
	return  1 if (${$a}[0] > ${$b}[0]);
	return 0;
}
sub mycmp_ascend {
	return  1 if (${$a}[0] < ${$b}[0]);
	return -1 if (${$a}[0] > ${$b}[0]);
	return 0;
}

#                     0    1    2
# OUT push(@summary, [$key,$siz,$blk,0]);
sub mycmp_ascend_2 {
	return -1 if (${$a}[1] < ${$b}[1]);
	return  1 if (${$a}[1] > ${$b}[1]);
	return 0;
}
sub mycmp_decend_2 {
	return  1 if (${$a}[1] < ${$b}[1]);
	return -1 if (${$a}[1] > ${$b}[1]);
	return 0;
}

# $ref_sum = push(@summary, [$key,$siz,$blk,0]);
sub mycmp_ascend_a {
	return -1 if (${$a}[0] lt ${$b}[0]);
	return  1 if (${$a}[0] gt ${$b}[0]);
	return 0;
}
sub mycmp_decend_a {
	return  1 if (${$a}[0] lt ${$b}[0]);
	return -1 if (${$a}[0] gt ${$b}[0]);
	return 0;
}


sub output_file_list($) {  # \@file
   my ($ra_in) = @_;
   my ($file,$i,$min,$len,$cnt,$num,$ra,@arr);
   if ($sort_per_size) {
      if ($sort_decending) {
         @arr = sort mycmp_ascend @{$ra_in};
      } else {
         @arr = sort mycmp_decend @{$ra_in};
      }
      $ra = \@arr;
   # } elsif ($sort_alpha) {

   } else {
      $ra = $ra_in;
   }
   $cnt = scalar @{$ra};
   $min = 0;
   for ($i = 0; $i < $cnt; $i++) {
      $file = ${$ra}[$i][1];
      $len = length($file);
      $min = $len if ($len > $min);
   }
   prt( "[VERB2] List of $cnt files in root...\n" );
   for ($i = 0; $i < $cnt; $i++) {
      $file = ${$ra}[$i][1];
      $file .= ' ' while (length($file) < $min);
      $num  = get_aligned_size_stg(${$ra}[$i][0]);
      prt( "$file $num\n" ); 
   }
}

sub process_dir($$) {
   my ($dir,$lev) = @_;
   my (@files,$file,$ff,$sb,$DIR);
   my %hash = ();
   if ( !opendir($DIR,$dir) ) {
      prtw("WARNING: Unable to open directory [$dir]!\n");
      return \%hash;
   }
   @files = readdir($DIR);
   closedir($DIR);
   my @dirs = ();
   my @fils = ();
   if ($lev) {
      prtsot('.'); # if ($lev < 2);
   } else {
      prt( "Processing directory [$dir]...($lev)\n" ); # < 2;
   }
   foreach $file (@files) {
      next if (($file eq '.')||($file eq '..'));
      $ff = $dir;
      $ff .= "\\" if ( !($dir =~ /(\\|\/)$/) );
      $ff .= $file;
      if ( $sb = stat($ff) ) {
         if (-d $ff) {
            if ($recursive) {
               push(@dirs,[$sb->size,$file,$ff,$sb->mtime,$lev,0]);
            }
         } elsif (-f $ff) {
            push(@fils,[$sb->size,$file,$ff,$sb->mtime,$lev,0]);
         } else {
            prtw("WARNING: WHAT IS THIS? [$ff]\n");
         }
      } else {
         prtw("WARNING: Unable to 'stat' [$ff]!\n");
      }
   }

   output_file_list(\@fils) if (($lev == 0) && VERB2() );

   $hash{$dir}{'DIRS'} = \@dirs;
   $hash{$dir}{'FILS'} = \@fils;

   return \%hash;
}

sub get_stg_left_aligned($$) {
   my ($stg,$min) = @_;
   $stg = ' '.$stg while (length($stg) < $min);
   return $stg;
}

sub get_aligned_file_size($) {
   my ($size) = shift;
   #use $fl_minn = 16; and $ks_mink = 8;
   return get_stg_left_aligned(get_nn($size),$fl_minn);
}

sub get_aligned_ks_size($) {
   my ($size) = shift;
   #use $fl_minn = 16; and $ks_mink = 8;
   return get_stg_left_aligned(b2ks2($size), $ks_mink);
}

sub get_aligned_size_stg($) {
   my ($size) = shift;
   #use $fl_minn = 16; and $ks_mink = 8;
   my $fsz = get_aligned_file_size($size);
   my $ksz = get_aligned_ks_size($size);
   return "$fsz $ksz";
}

sub get_size_stg($) {
   my ($size) = shift;
   my $msg = " ".get_nn($size)." (".b2ks2($size).")";
   return $msg;
}

sub process_file_array_ref($$) {
   my ($far_in,$rootdir) = @_;
   my (@sarr);
   if ($sort_decending) {
      @sarr = sort mycmp_ascend @{$far_in};
   } else {
      @sarr = sort mycmp_decend @{$far_in};
   }
   my $far = \@sarr;
   my ($ff,$file,$size,$cnt,$i);
   my ($total_size,$total_blocks,$minfl,$len,$minsz);
   my ($blks,$dsize,$dvd_num,$tsize,$tmp,$msg);
   my ($j,$size2,$blks2,$dsize2,$file2);
   $cnt = scalar @{$far_in};
   $total_size = 0;
   $total_blocks = 0;
   $minfl = 0;
   $minsz = 0;
   $tsize = 0;
   #             0         1     2    3         4    5
   # push(@fils,[$sb->size,$file,$ff,$sb->mtime,$lev,0]);
   for ($i = 0; $i < $cnt; $i++) {
      $ff = ${$far}[$i][2];
      $file = ${$far}[$i][1];
      $size = ${$far}[$i][0];
      $len = length($file);
      $minfl = $len if ($len > $minfl);

      $total_size += $size;
      $blks = int($size / $block);
      $blks++ if (($size % $block)||($size == 0));
      $total_blocks += $blks;
      $dsize = $blks * $block;
      $tmp = get_nn($dsize);
      $len = length($tmp);
      $minsz = $len if ($len > $minsz);
      #prt( "$file $size\n" );
      ${$far}[$i][5] = 0;   # clear DONE
      $tsize += $dsize; # accumulate total, by each file in root
   }
   $blks = $total_blocks * $block;
   prt( "Total $cnt files, total size = $total_size ($blks) or ".b2ks2($total_size)." (".b2ks2($blks).")\n" );

   $dvd_num = 1;
   #if ($blks > $max_cd) {
   if ($tsize > $max_cd) {
      $tsize = 0;   # restart total size for THIS DVD
      for ($i = 0; $i < $cnt; $i++) {
         next if (${$far}[$i][5]);  # skip it if DONE
         $ff = $sarr[$i][2];
         $file = $sarr[$i][1];
         $size = $sarr[$i][0];
         ${$far}[$i][5] = 1;    # DONE THIS FILE
         $blks = int($size / $block);
         $blks++ if (($size % $block)||($size == 0));
         $dsize = $blks * $block;
         if ($dsize > $max_cd) {
            # YEEK, this ONE FILE *GT* DVD SIZE
            if ($tsize) {
                if ($fill_each_dvd) {
                    # seek any smaller file to add to this DVD
                    for ($j = 0; $j < $cnt; $j++) {
                        next if (${$far}[$j][5]);  # skip it if DONE
                        $size2 = $sarr[$j][0];
                        $file2 = $sarr[$j][1];
                        $blks2 = int($size2 / $block);
                        $blks2++ if (($size2 % $block)||($size2 == 0));
                        $dsize2 = $blks2 * $block;
                        $tmp = get_aligned_size_stg($dsize2);
                        prt( "[dbg_01] Check $file2 $tmp \n") if ($dbg_01);
                        if (($tsize + $dsize2) <= $max_cd) {
                            # found one that can be ADDED
                            if (VERB1()) {
                                $file2 .= ' ' while (length($file2) < $minfl);
                                prt("$file2 $tmp - ADDED\n");
                            }
                            $tsize += $dsize2;
                            ${$far}[$j][5] = 1;    # DONE THIS FILE
                        }
                    }
                }
               $msg = "$dvd_num: SUBTOTAL ";
               $msg .= " " while (length($msg) < $minfl);
               $msg .= $msg_sub_add;
               #prt( "$dvd_num: Subtotal ".get_size_stg($tsize)."\n" );
               #prt( "$msg".get_size_stg($tsize)."\n" );
               $tmp = get_aligned_size_stg($tsize);
               prt( "$msg $tmp\n" );
               $dvd_num++;
            }
            if (VERB1()) {
               $file .= ' ' while (length($file) < $minfl);
               $tmp = get_aligned_size_stg($dsize);
               prt("$file $tmp\n");
            }
            $msg = "$dvd_num: SUBTOTAL ";
            $msg .= " " while (length($msg) < $minfl);
            $msg .= $msg_sub_add;
            #prt( "$dvd_num: Subtotal ".get_size_stg($dsize)." - NEEDS FURTHER SPLIT\n" );
            #prt( "$msg".get_size_stg($dsize)." - NEEDS FURTHER SPLIT\n" );
            $tmp = get_aligned_size_stg($dsize);
            if (!VERB1()) {
                prt( "$msg $tmp - file [$file(".b2ks2($size).")] NEEDS FURTHER SPLIT!\n" );
            } else {
                prt( "$msg $tmp - NEEDS FURTHER SPLIT!\n" );
            }
            $dvd_num++;
            $tsize = 0;
            next;   # go for NEXT
         } elsif (($tsize + $dsize) > $max_cd) {
            # Ok, current rnning TOTAL PLUS THIS FILE GT DVD SIZE
            if ($fill_each_dvd) {
                # seek any smaller file to add to this DVD
                for ($j = 0; $j < $cnt; $j++) {
                    next if (${$far}[$j][5]);  # skip it if DONE
                    $size2 = $sarr[$j][0];
                    $file2 = $sarr[$j][1];
                    $blks2 = int($size2 / $block);
                    $blks2++ if (($size2 % $block)||($size2 == 0));
                    $dsize2 = $blks2 * $block;
                    $tmp = get_aligned_size_stg($dsize2);
                    prt( "[dbg_01] Check $file2 $tmp \n") if ($dbg_01);
                    if (($tsize + $dsize2) <= $max_cd) {
                        # found one that can be ADDED
                        if (VERB1()) {
                            $file2 .= ' ' while (length($file2) < $minfl);
                            prt("$file2 $tmp - ADDED\n");
                        }
                        $tsize += $dsize2;
                        ${$far}[$j][5] = 1;    # DONE THIS FILE
                    }
                }
            }
            $msg = "$dvd_num: SUBTOTAL ";
            $msg .= " " while (length($msg) < $minfl);
            $msg .= $msg_sub_add;
            #prt( "$dvd_num: Subtotal ".get_size_stg($tsize)."\n" );
            #prt( "$msg".get_size_stg($tsize)."\n" );
            $tmp = get_aligned_size_stg($tsize);
            prt( "$msg $tmp\n" );
            $tsize = 0;
            $dvd_num++;
         }
         $tsize += $dsize;  # add this size to TOTAL CURRENT DVD size
         if (VERB1()) {
            $file .= ' ' while (length($file) < $minfl);
            #prt("$file $dsize (".b2ks2($dsize).")\n");
            #$tmp = get_nn($dsize);
            #$tmp = " $tmp" while (length($tmp) < $minsz);
            #prt("$file $tmp (".b2ks2($dsize).")\n");
            $tmp = get_aligned_size_stg($dsize);
            prt("$file $tmp\n");
         }
      }
   } else {
       # root files will ALL fit on ONE DVD
       if (VERB1()) {
           if ($cnt) {
               for ($i = 0; $i < $cnt; $i++) {
                    # want LIST of files
                    $ff = $sarr[$i][2];
                    $file = $sarr[$i][1];
                    $size = $sarr[$i][0];
                    $blks = int($size / $block);
                    $blks++ if (($size % $block)||($size == 0));
                    $dsize = $blks * $block;
                    $file .= ' ' while (length($file) < $minfl);
                    $tmp = get_aligned_size_stg($dsize);
                    prt("$file $tmp\n");
               }
           } else {
               prt("There are NO files to list in the 'root' folder....\n");
           }
       }
   }

   if ($tsize) {
      $msg = "$dvd_num: SUBTOTAL ";
      $msg .= " " while (length($msg) < $minfl);
      $msg .= $msg_sub_add;
      #prt( "$dvd_num: Subtotal ".get_size_stg($tsize)."\n" );
      #prt( "$msg".get_size_stg($tsize)."\n" );
      $tmp = get_aligned_size_stg($tsize);
      prt( "$msg $tmp\n" );
   }
   if ($total_blocks) {
       prt("For [$rootdir], need $dvd_num DVDS, for total ".get_size_stg($total_blocks * $block));
       if ($got_exclude_root) {
          prt(",\n but root files are EXCLUDED.");
       }
       prt("\n");
       # my ($j,$size2,$blks2,$dsize2,$file2);
       $size2 = $total_blocks * $block;
       $j = int( $size2 / $max_cd );
       $dsize2 = $size2 - ($j * $max_cd); 
       $j++ if ($dsize2);
       prt("So this root needs $j dvds, if evenly split.. last dvd with ".b2ks2($dsize2)." bytes.\n") if ($j > $dvd_num);
   } else {
        prt("No files in root [$rootdir]...\n") if (VERB9());
   }

   my @rtots = ();
   # prt( "push(\@rtots, [ $total_size, $total_blocks, $tsize, $dvd_num ]);\n" );
   push(@rtots, [ $total_size, $total_blocks, $tsize, $dvd_num ]);
   return \@rtots;
}

sub process_dir_array_ref($$$) {
   my ($rdirs,$rhash,$lev) = @_;
   my $cnt = scalar @{$rdirs};
   my ($i,$dir,$rdh,$rd2);
   #my %hash = ();
   for ($i = 0; $i < $cnt; $i++) {
      #             0         1     2   3
      # push(@dirs,[$sb->size,$file,$ff,$sb->mtime]);
      $dir = ${$rdirs}[$i][2];
      $rdh = process_dir($dir,$lev);
      ${$rhash}{$dir} = $rdh;
      #$hash{$dir} = $rdh;
      $rd2 = ${$rdh}{$dir}{'DIRS'};
      process_dir_array_ref($rd2,$rhash,($lev + 1));
   }
   #foreach $dir (keys %hash) {
   #   $rdh = $hash{$dir};
   #   $rd2 = ${$rdh}{$dir}{'DIRS'};
   #   process_dir_array_ref($rd2,$rhash,($lev + 1));
   #}
}

sub remove_base2($$) {
   my ($file,$key) = @_;
   my $len = length($file);
   if (($len+1) < length($key)) {
      # remove the base
      return substr($key,($len+1));
   }
   return $key;
}

sub process_full_hash($$) {
   my ($rhash,$base) = @_;
   my ($dcnt,$rdh,$rfils,$fcnt);
   $dcnt = scalar keys(%{$rhash});
   prt( "Got $dcnt keys to process...\n" );
   my ($key,$skey,$nkey,$i,$ff,$fil,$siz);
   my ($size,$total_size);
   $nkey = '';
   $total_size = 0;
   my @dir_array = ();
   foreach $key (sort keys(%{$rhash})) {
      $rdh = ${$rhash}{$key};
      if ($key eq '*FILES_ARRAY*') {
         prt("Processing key [$key]...\n") if (VERB2());
      } elsif ($key eq '*DIRECTORY_ARRAY*') {
         prt("Processing key [$key]...\n") if (VERB2());
      } else {
         # $hash{$dir}{'DIRS'} = \@dirs;
         # $hash{$dir}{'FILS'} = \@fils;
         $rfils = ${$rdh}{$key}{'FILS'};
         $fcnt = scalar @{$rfils};
         $skey = remove_base2($base,$key);
         if ( !($skey =~ /(\\|\/)/) ) {
            # if a base subdirectory...
            if (length($nkey)) {
               prt( "Done [$nkey] total = $total_size\n" ) if (VERB2());
               push(@dir_array, [ $nkey, $total_size ]);
            }
            prt( "Processing base [$skey]\n" ) if (VERB2());
            $nkey = $skey;
            $total_size = 0;
         }
         for ($i = 0; $i < $fcnt; $i++) {
            $ff  = ${$rfils}[$i][2];
            $fil = ${$rfils}[$i][1];
            $siz = ${$rfils}[$i][0];
            $total_size += $siz;
         }
      }
   }
   if (length($nkey)) {
      prt( "Done [$nkey] total = $total_size\n" ) if (VERB2());
      push(@dir_array, [ $nkey, $total_size ]);
   }
   ${$rhash}{'*DIRECTORY_ARRAY*'} = [ @dir_array ];
   return \@dir_array;
}

#1234567890123456
#000,000,000,000
sub show_hash_reference($) {
   my ($hr) = @_;
   my $rdh = ${$hr}{'*FILES_ARRAY*'};
   my $rda = ${$hr}{'*DIRECTORY_ARRAY*'};
   my ($dir,$rdirs,$rfils,$dcnt,$fcnt,$i,$siz,$size);
   my ($min,$len);
   my $minn = $fl_minn; # = 16;
   if (defined $rdh) {
      foreach $dir (keys %{$rdh}) {
         $rdirs = ${$rdh}{$dir}{'DIRS'};
         $rfils = ${$rdh}{$dir}{'FILS'};
         $dcnt = scalar @{$rdirs};
         $fcnt = scalar @{$rfils};
         prt( "Got $fcnt files, from [$dir], and $dcnt directories...\n" );
      }
   }
   if (defined $rda) {
      $dcnt = scalar @{$rda};
      $min = 0;
      for ($i = 0; $i < $dcnt; $i++) {
         $dir = ${$rda}[$i][0];
         $len = length($dir);
         $min = $len if ($len > $min);
      }
      for ($i = 0; $i < $dcnt; $i++) {
         $dir = ${$rda}[$i][0];
         $size = ${$rda}[$i][1];
         $siz = get_nn($size);
         $dir .= ' ' while (length($dir) < $min);
         $siz = ' '.$siz while (length($siz) < $minn);
         prt( "$dir | $siz (".b2ks2($size).")\n" );
      }
   }
   
}

sub is_in_excluded($) {
   my ($dir) = shift;
   return 1 if (defined $exclude_dirs{$dir});
   return 0;
}

sub dir_is_in_excluded($) {
   my ($path) = shift;
   my @arr = split(/(\\|\/)/, $path);
   foreach my $dir (@arr) {
      if (defined $exclude_dirs{$dir}) {
         return 1;
      }
   }
   return 0;
}


sub find_local_files($) {
   my ($dirs) = @_;
   my %file_list = ();
   # $File::Find::dir  - is the current directory name, 
   # $_                - is the current filename within that directory 
   # $File::Find::name - is the complete pathname to the file.
   # eg
   # $File::Find::dir  = /some/path/
   # $_                = foo.ext
   # $File::Find::name = /some/path/foo.ext
   local *wanted_files = sub {
      push (@{$file_list{$File::Find::dir}}, $_);
   };

   File::Find::find(\&wanted_files, @{$dirs});

   return \%file_list;
}

sub process_dir_hash($$$) {
   my ($rdirs,$rhash,$rootdir) = @_;
   my $cnt = scalar @{$rdirs};
   my ($i,$dir,$rdh,$rd2);
   #my %hash = ();
   my $bgn_secs = time();
   my $skipped = 0;
   return if (!$cnt);
   prt( "Doing $cnt sub-directories of [$rootdir], with File::Find...\n" ); 
   for ($i = 0; $i < $cnt; $i++) {
      #             0         1     2   3
      # push(@dirs,[$sb->size,$file,$ff,$sb->mtime]);
      $dir = ${$rdirs}[$i][2];
      if ( dir_is_in_excluded($dir) ) {
         if (VERB5()) {
            prt("Excluded directory [$dir]\n");
         } else {
            prtso(".") if (VERB2());
         }
         $skipped++;
         next;
      } else {
         if (VERB5()) {
            prt("Processing folder [$dir]\n");
         } else {
            prtso(".") if (VERB2());
         }
      }
      # find_local_files return \%file_list;
      ${$rhash}{$dir}{'FF'} =  find_local_files( [$dir] );
   }
   prtso("\n") if (VERB2() && !VERB5());
   if ($got_exclude_dirs) {
      if ($skipped) {
         if ($skipped == $got_exclude_dirs) {
            prt("Skipped $skipped of $got_exclude_dirs excluded directories.\n") if (VERB2());
         } else {
            prtw("WARNING: Skipped $skipped of $got_exclude_dirs excluded directories!\n");
         }
      } else {
         prtw("WARNING: Got $got_exclude_dirs excluded directories, BUT NONE found!\n");
      }
   }
   my $elap_secs = time() - $bgn_secs;
   prt( "Done $cnt sub-directories, in $elap_secs seconds, with File::Find...\n" ) if (VERB5());
}

sub remove_base($$) {
   my ($file,$key) = @_;
   my $len = length($file);
   my $base = '';
   if ($len < length($key)) {
      # remove the base
      $base = substr($key,$len);
      $base =~ s/^(\\|\/)//;
      return $base;
   } elsif ($len == length($key)) {
      return '.';
   }
   return $key;
}

sub expand_dir_hash($$$) {
   my ($rdirs,$rhash,$base) = @_;
   # ${$rhash}{$dir}{'FF'} =  find_local_files( [$dir] );
   #    push (@{$file_list{$File::Find::dir}}, $_);
   my $dircnt = scalar keys(%{$rhash});
   my ($dir,$rff,$item,$fcnt,$dcnt,$ff,$fref);
   my ($ditem,$fcnt2,$file,$sb,$sitem);
   my ($tsize,$kb,$flist,$size,$blks,$tblks,$tbsize);
   my ($sdir,$len,$min,$cnt);
   my %hash = ();
   if (!$dircnt) {
      return \%hash;
   }
   prt("Expanding [$base] sub-directory hash for $dircnt keys...\n") if (VERB3());
   $min = 0;
   my $bgtime = time();
   foreach $dir (keys(%{$rhash})) {
      $sdir = remove_base($base,$dir);
      $len = length($sdir);
      $min = $len if ($len > $min);
   }
   foreach $dir (sort keys(%{$rhash})) {
      $rff = ${$rhash}{$dir}{'FF'};
      $cnt = scalar keys(%{$rff});
      $sdir = remove_base($base,$dir);
      if (VERB5()) {
         prt("dir: ".sprintf("%".$min."s", $sdir)." - ");
      } else {
         prtso(".") if (VERB2());
      }
      $fcnt = 0;
      $dcnt = 0;
      $fcnt2 = 0;
      $tsize = 0;
      $flist = '';
      $tblks = 0;
      foreach $item (keys %{$rff}) {
         $fref = ${$rff}{$item};
         $fcnt += scalar @{$fref};
         $ditem = $item;
         $ditem =~ s/\//\\/g;
         $sitem = remove_base($dir,$item);
         $flist .= '|' if (length($flist));
         $flist .= "$sitem($fcnt)";
         # array of file, and directory entries
         if (-d $ditem) {
            $dcnt++;
            $ditem .= "\\" if ( !($ditem =~ /\\$/) );
            foreach $file (@{$fref}) {
               $ff = $ditem . $file;
               if ($sb = stat($ff)) {
                  $size = $sb->size;
                  $blks = int($size / $block);
                  $blks++ if (($size % $block)||($size == 0));
                  #push(@{$hash{$sitem}}, [$file, $size, $sb->mtime, $blks]);
                  $tsize += $size;
                  $tblks += $blks;
               } else {
                  prt("\n");
                  prtw("WARNING: NO STAT ON [$ff]!\n");
               }
            }
         } elsif (-f $ditem) {
            $fcnt2++;
         } else {
            prt("\n");
            prtw("WARNING: GOT [$item] or [$ditem] NOT FILE OR DIRECTORY!\n");
            #prt( Dumper($rff) );
         }
      }
      $kb = b2ks2($tsize);
      $tbsize = $tblks * $block;
      push(@{$hash{$sdir}}, [$tsize, $tblks]);
      prt( sprintf("%4u",$fcnt)." files, ".get_aligned_size_stg($tsize).", or ".get_aligned_file_size($tbsize)." on disk.\n" ) if (VERB2());
      prt( "In $dcnt($cnt) folders... [$flist]\n" ) if (VERB3());
   }
   prtso("\n") if (VERB2() && !VERB5());
   my $difftime = time() - $bgtime;
   prt("Done $dircnt expansions, in $difftime seconds...\n") if (VERB9());
   return \%hash;
}

sub no_case_ascend {
   my $lca = lc($a);
   my $lcb = lc($b);
	return -1 if ($lca lt $lcb);
	return 1 if ($lca gt $lcb);
	return 0;
}


# IN  show_dir_sizes($ref_hash,$ref_rt,$file);
# OUT push(@summary, [$key,$siz,$blk,0]);
sub show_dir_sizes($$$) {
   my ($rh,$rt,$root) = @_;
   # push(@{$hash{$sdir}}, [$tsize, $tblks]);
   my @arr = sort no_case_ascend keys(%{$rh});
   my ($key,$min,$len,$minn);
   my ($rsa,$rsaa,$siz,$blk,$csiz);
   my ($cblk,$kblk,$mink,$tmp);
   my $tot_size = 0;
   my $tot_blks = 0;
   my $dircnt = scalar @arr;
   $minn = $fl_minn; # 16;
   $mink = $ks_mink; # 8;
   $min = 0;
   my @summary = ();
   if (!$dircnt) {
      return \@summary;
   }
   prt("Getting summary of $dircnt folders, in [$root]...\n");
   foreach $key (@arr) {
      $len = length($key);
      $min = $len if ($len > $min);
   }

   # Add the ROOT to the SUMMARY
   if ( ! $got_exclude_root ) {
      $key = "$root (*)";
      $len = length($key);
      $min = $len if ($len > $min);
      $rsa = ${$rt}[0]; # hmmm, WHY is this double layered???
      $siz = ${$rsa}[0];
      $blk = ${$rsa}[1];
      push(@summary, [$key,$siz,$blk,0]);
      $tmp = $blk * $block;
      # prt( "push(\@summary, [$key,$siz,$blk,0]); ($blk * $block = $tmp)\n");
      $tot_size += $siz;
      $tot_blks += $blk;
      if (VERB2()) {
         $key .= ' ' while (length($key) < $min);
         $csiz = get_nn($siz);
         $csiz = ' '.$csiz while (length($csiz) < $minn);
         $cblk = get_nn($blk * $block);
         $cblk = ' '.$cblk while (length($cblk) < $minn);
         $kblk = b2ks2($blk * $block);
         $kblk = ' '.$kblk while (length($kblk) < $mink);
         prt("$key | $csiz ($cblk $kblk) ".sprintf("%8u",$blk)." blocks\n");
      }
   }

   foreach $key (@arr) {
      $rsaa = ${$rh}{$key};
      #prt( Dumper($rsa) );
      #exit(1);
      $rsa = ${$rsaa}[0];  # hmmm, WHY is this double layered???
      $siz = ${$rsa}[0];
      $blk = ${$rsa}[1];
      push(@summary, [$key,$siz,$blk,0]);
      # prt( "push(\@summary, [$key,$siz,$blk,0]);\n" );
      $tot_size += $siz;
      $tot_blks += $blk;
      if (VERB2()) {
         $key .= ' ' while (length($key) < $min);
         $csiz = get_nn($siz);
         $csiz = ' '.$csiz while (length($csiz) < $minn);
         $cblk = get_nn($blk * $block);
         $cblk = ' '.$cblk while (length($cblk) < $minn);
         $kblk = b2ks2($blk * $block);
         $kblk = ' '.$kblk while (length($kblk) < $mink);
         prt("$key | $csiz ($cblk $kblk) ".sprintf("%8u",$blk)." blocks\n");
      }
   }

   $key = "TOTAL: ";
   if (VERB2()) {
      $key .= ' ' while (length($key) < $min);
   }

   $csiz = get_nn($tot_size);
   $csiz = ' '.$csiz while (length($csiz) < $minn);
   $cblk = get_nn($tot_blks * $block);
   $cblk = ' '.$cblk while (length($cblk) < $minn);
   $kblk = b2ks2($tot_blks * $block);
   $kblk = ' '.$kblk while (length($kblk) < $mink);
   prt("$key | $csiz ($cblk $kblk) ".sprintf("%8u",$tot_blks)." blocks\n");
   prt("Done summary of $dircnt folders, in [$root]...\n");
   return \@summary;
}

sub add_padding($$) {
   my ($rtxt,$min) = @_;
   ${$rtxt} = ' '.${$rtxt} while (length(${$rtxt}) < $min);
}


# divide_for_dvd($ref_sum,$ref_rt,$file);
# $ref_sum = push(@summary, [$key,$siz,$blk,0]);
sub divide_for_dvd($$$) {
   my ($ra_in,$rroot,$rootdir) = @_;
   my ($ra,@arr);
   if ($sort_per_size) {
      if ($sort_decending) {
         @arr = sort mycmp_decend_2 @{$ra_in};
      } else {
         @arr = sort mycmp_ascend_2 @{$ra_in};
      }
      $ra = \@arr;
   } elsif ($sort_alpha) {
      if ($sort_decending) {
         @arr = sort mycmp_decend_a @{$ra_in};
      } else {
         @arr = sort mycmp_ascend_a @{$ra_in};
      }
      $ra = \@arr;
   } else {
      $ra = $ra_in;
   }
   my $cnt = scalar @{$ra};
   if (!$cnt) {
       prt( "No count, so divide_for_dvd function abandoned...\n") if (VERB9());
       return;
   }
   my ($i,$dir,$siz,$blk,$min,$len,$tot_blks,$cblks);
   my ($bpdvd,$dvd_num,$msg,$dsize);
   my ($form,$tmp1,$tmp2,$tmp3,$tmp4);
   my ($j,$blk2,$siz2,$msg2,$rem,$dsize2,$dir2,$tmp);
   my ($srched,$added);
   $min = 0;
   $tot_blks = 0;
   $cblks = 0;
   $dvd_num = 1;
   $bpdvd = int($max_cd / $block);
   prt( "Division to DVD blocks, on $cnt items... max $bpdvd blocks [".get_size_stg($max_cd)."]\n" );
   for ($i = 0; $i < $cnt; $i++) {
      $dir = ${$ra}[$i][0];
      $siz = ${$ra}[$i][1];
      $blk = ${$ra}[$i][2];
      ${$ra}[$i][3] = 0;   # clear DONE flag
      $len = length($dir);
      $min = $len if ($len > $min);
      $tot_blks += $blk;
      $dsize = $blk * $block;
      if ($blk > $bpdvd) {
         if ($give_sprtf_a_go) {
            $form = '%'.$min.'s'." %14L %14L";
            $msg = sprintf( $form, $dir, $dsize, $blk);  # FAILS WITH LARGE INTEGERS!!!
         } else {
            $tmp1 = $dir;
            # add_padding(\$tmp1,$min);
            $tmp2 = get_aligned_size_stg($dsize);
            $tmp3 = "$blk";
            add_padding(\$tmp3,10);
            $msg = $tmp1.$tmp2.$tmp3;
         }
         $msg = substr($msg,1) while ($msg =~ /^\s/);
         prt("NOTE: [$msg] NEEDS FURTHER SPLITTING\n") if (VERB3());
         #prt( "blocks $blk * $block = $dsize\n");
      }
   }
   
   $form = '%'.$min.'s'." %14Lu %14I64u"; # seems L, ll, even I64 all FAIL in WIN32
   for ($i = 0; $i < $cnt; $i++) {
      next if (${$ra}[$i][3]);   # already DONE
      $dir = ${$ra}[$i][0];
      $siz = ${$ra}[$i][1];
      $blk = ${$ra}[$i][2];
      ${$ra}[$i][3] = 1;         # set DONE flag
      $dsize = $blk * $block;
      if ($give_sprtf_a_go) {
         $msg = sprintf( $form, $dir, $dsize, $blk);
      } else {
         $tmp1 = $dir;
         add_padding(\$tmp1,$min);
         $tmp2 = get_aligned_size_stg($dsize);
         $tmp3 = "$blk";
         add_padding(\$tmp3,10);
         $msg = $tmp1.$tmp2.$tmp3;
      }
      if ($blk > $bpdvd) {
         $tmp = $blk;   # put BLOCKS of this directory into a TEMP
         if ($cblks) {
            # try to FILL this with some from the LARGE...
            $rem = $bpdvd - $cblks; # get REMAINDER blocks on this DVD, about to be CLOSED
            $tmp -= $rem;           # remove this remainder from the LARGE
            $cblks += $rem;         # and ADD to this DVD blocks
            prt("End DVD $dvd_num: ".get_size_stg($cblks * $block).", filled $rem blocks from [$dir] [".get_size_stg($rem * $block)."]\n");
            $dvd_num++;             # closed this DVD
            $cblks = 0;
         }
         while ($tmp > $bpdvd) {
            # block count still above a DVD size
            prt( "$dvd_num: $msg = Note, $bpdvd of $tmp blocks put on this DVD!\n" );
            $dvd_num++;
            $tmp -= $bpdvd;            # subtract ONE DVD of blocks
            $msg = "$dir";             # reduce message to just DIRECTORY name
            add_padding(\$msg,$min);   # and fill out the length
         }
         prt( "$dvd_num: $msg - Note, $tmp of $blk blocks carried to next DVD! [".get_size_stg($tmp * $block)."]\n" ) if ($tmp);
         $cblks = $tmp;       # start this new DVD, with this remainder, if ANY
         next;                # and go get NEXT item
      } elsif (($cblks + $blk) > $bpdvd) {
         if ($cblks) {
            # try to FILL this with some smaller directory...
            $rem = $bpdvd - $cblks;
            $srched = -1;
            $added  = 0;
            if ($rem > 10) {   # if there is room for at least 10 blocks
               $srched = 0;
               for ($j = 0; $j < $cnt; $j++) {  # go through the LIST again
                  next if (${$ra}[$j][3]);      # SKIP if already DONE
                  $blk2 = ${$ra}[$j][2];        # get its block size
                  $srched++;
                  if ($blk2 < $rem) {           # if LESS than remainder
                     # got ONE, ADD it to THIS DVD
                     $dir2 = ${$ra}[$j][0];     # extract DIRECTORY
                     $siz2 = ${$ra}[$j][1];     # and size
                     ${$ra}[$j][3] = 1;         # set DONE flag
                     $dsize2 = $blk2 * $block;
                     $tmp1 = $dir2;
                     add_padding(\$tmp1,$min);
                     $tmp2 = get_aligned_size_stg($dsize2);
                     $tmp3 = "$blk2";
                     add_padding(\$tmp3,10);
                     $msg2 = $tmp1.$tmp2.$tmp3;
                     prt( "$dvd_num: $msg2 ($j): Added to DVD [".get_size_stg($siz2)."]\n" );
                     $rem -= $blk2;
                     $cblks += $blk2;
                     $added++;
                  }
               }
            }
            prt("End DVD $dvd_num: ".get_size_stg($cblks * $block));
            if ($srched == -1) {
               prt(" No srch - due rem($rem) < 10" );
            } elsif ($srched == 0) {
               prt(" No srch - none not Done of $cnt!" );
            } else {
               if ($added) {
                  prt(" Srched $srched, of $cnt, added $added, rem=$rem" );
               } else {
                  prt(" Srched $srched, of $cnt, but none less that rem=$rem" );
               }
            }
            prt("\n");
            $dvd_num++;
            $cblks = 0;
         }
         $cblks = 0;
      }
      $cblks += $blk;
      prt( "$dvd_num: $msg (".($i+1).")\n" );
   }
   if ($cblks) {
      $tmp = int(($cblks * 10000) / $bpdvd);
      $tmp /= 100;
      prt("End DVD $dvd_num: ".get_size_stg($cblks * $block)." ($tmp".'%'.")\n");
   }
   # summary - what it is all about
   # ==============================
   prt( "For [$rootdir] need $dvd_num DVDs for ".get_size_stg($tot_blks * $block) );
   if ($got_exclude_root) {
      prt( ", excluding ROOT" );
   }
   if ($got_exclude_dirs) {
      prt(",\n excluding $got_exclude_dirs dir(s) [");
      foreach $tmp (keys %exclude_dirs) {
         prt("$tmp ");
      }
      prt("]");
   }
   prt("\n");
}

sub process_in_files($) {
   my ($rinfs) = shift;
   my ($file,$rdh,$rdirs,$rfils,$dcnt,$fcnt,$rfd);
   my %hash = ();
   my %hash2 = ();
   foreach $file (@{$rinfs}) {
      if (-d $file) {
         $rdh = process_dir($file,0);
         $hash{'*FILES_ARRAY*'} = $rdh;
         $rdirs = ${$rdh}{$file}{'DIRS'};
         $rfils = ${$rdh}{$file}{'FILS'};
         $dcnt = scalar @{$rdirs};
         $fcnt = scalar @{$rfils};
         if ($recursive) {
            prt( "Got $dcnt directories, and $fcnt files, from [$file]\n" );
         } else {
            prt( "Got $fcnt files, from [$file] - recursive is OFF.\n" );
         }
         my $ref_rt = process_file_array_ref($rfils,$file);     # count the files in the ROOT space
         if ($use_old_way) {
            # this was TOO SLOW, so tried another WAY ;=))
            my $bgn_secs = time();
            process_dir_array_ref($rdirs,\%hash,1);
            my $elap_secs = time() - $bgn_secs;
            prt( "\nDone $dcnt directories in $elap_secs seconds...\n" );
            process_full_hash(\%hash,$file);
         } else {
            process_dir_hash($rdirs,\%hash2,$file);   # get all the sub-directories
            my $ref_hash = expand_dir_hash($rdirs,\%hash2,$file);
            my $ref_sum = show_dir_sizes($ref_hash,$ref_rt,$file);
            divide_for_dvd($ref_sum,$ref_rt,$file);
         }
      }
   }
   return \%hash;
}


# =============================
# MAIN
parse_arguments(@ARGV);
$| = 1;
if (@in_files) {
    my $hash_ref = process_in_files(\@in_files);
    if ($use_old_way) {
       show_hash_reference($hash_ref);
    }
} else {
    pgm_exit(1,"No input directory to process... Try -?");
}
pgm_exit(0,"Normal exit");
# =============================


# Ensure argument exists, or die.
sub require_argument {
    my ($arg, @arglist) = @_;
    if (!@arglist) {
       prt( "ERROR: no argument given for option '$arg', and one is required!\n" );
       pgm_exit(1,"Bad parameter");
    }
}

# -i <FILE> fo rinput
sub deal_with_i_opt($) {
   my ($arg) = shift;
   if ( ! -f $arg) {
      prt("ERROR: Can not locate input file '$arg'!");
      pgm_exit(1,"No file");
   }
   if ( !open (INF, "<$arg") ) {
      prt("ERROR: Unable to OPEN file '$arg'!");
      pgm_exit(1,"File Error");
   }
   my @la = <INF>;	# slurp whole file
   close(INF);
   foreach my $f (@la) {
      chomp $f;
      if (length($f) > 0) {
         if ( -f $f ) {
            prtv1( "Storing file argument [$f].\n" );
            push(@in_files, $f);
         } elsif ( -d $f ) {
            prtv1( "Storing folder argument [$f].\n" );
            push(@in_files, $f);
         } else {
            prtw("WARNING: Can not locate '$f' item - discarding!");
         }
      }
   }
}

sub deal_with_v_opt($) {
   my ($arg) = shift;
   my ($tmp,$len,$i,$cc);
   if ($arg =~ /^-v(\d+)$/) {
       # -v<num>
       $tmp = $1;
       $verbose = $tmp;
   } elsif ($arg =~ /^-v/) {
      $verbose++;
      if ($arg =~ /^-v/) {
         $tmp = substr($arg,2);
         $len = length($tmp);
         # process for a set of vvvvv's - squeak if one is NOT a 'v'
         for ($i = 0; $i < $len; $i++) {
            $cc = substr($tmp,$i,1);
            if ($cc eq 'v') {
               $verbose++;
            } else {
               prt( "ERROR: unrecognised option? [$arg]! Try -? ... aborting...\n" );
               pgm_exit(1,"Bad -v Option");
            }
         }
      }
      prtv1( "Set verbose to $verbose\n" );
   }
}

# the SORT option
sub deal_with_s_opt($) {
   my ($arg) = shift;
   if ($arg eq '-soff') {
      $sort_per_size = 0;
      prtv1( "Set size sort OFF.\n" ) if (VERB1());
   } elsif ($arg eq '-son') {
      $sort_per_size = 1;
      prtv1( "Set size sort ON.\n" ) if (VERB1());
   } elsif ($arg eq '-sup') {
      $sort_per_size = 1;
      $sort_decending = 0;    # largest FIRST, else smallest first
      prtv1( "Set size sort ON, ascending.\n" ) if (VERB1());
   } elsif ($arg eq '-sdown') {
      $sort_per_size = 1;
      $sort_decending = 1;    # largest FIRST, else smallest first
      prtv1( "Set size sort ON, decending.\n" ) if (VERB1());
   } elsif ($arg =~ /^-sa/) {
      $sort_per_size = 0;
      $sort_alpha = 1;
      if ($arg eq '-sa') {
         prtv1( "Set for alpha sort.\n" );
      } elsif ($arg eq '-saup') {
         $sort_decending = 0;
         prtv1( "Set for alpha sort up - A to Z...\n" );
      } elsif ($arg eq '-sadown') {
         $sort_decending = 1;
         prtv1( "Set for alpha sort down - Z to A...\n" );
      } else {
         prt( "ERROR: unrecognised SORT ALPHA option? [$arg]! Try -? ... aborting...\n" );
         pgm_exit(1,"Bad -s Option");
      }
   } else {
      prt( "ERROR: unrecognised option? [$arg]! Try -? ... aborting...\n" );
      pgm_exit(1,"Bad -s Option");
   }
}

# -x <DIR> or -x @file_list
sub deal_with_x_opt($) {
   my ($arg) = shift;
   my @arr = split(';',$arg);
   foreach my $itm (@arr) {
      if (substr($itm,0,1) eq '@') {
         # assume an INPUT FILE
         $itm = substr($itm,1);
         if (open INF, "<$itm") {
            my @lns = <INF>;
            close INF;
            foreach my $ln (@lns) {
               chomp $ln;
               $ln = trim_all($ln);
               strip_dbl_quotes($ln);
               if ($ln eq '.') {
                  $got_exclude_root = 1;
                  prtv1("Setting exclude root...\n");
               } else {
                  $exclude_dirs{$ln} = 1;
                  prtv1("Setting exclude [$ln]...\n");
               }
            }
         } else {
            prt("ERROR: command [$arg]! Unable to open file [$itm]!!\n");
            pgm_exit(1,"Command Error");
         }
      } else {
         if ($itm eq '.') {
            $got_exclude_root = 1;
            prtv1("Setting exclude root...\n");
         } else {
            $exclude_dirs{$itm} = 1;
            prtv1("Setting exclude [$itm]...\n");
         }
      }
   }
}

sub give_help() {
   my $arg = '';
   $arg .= " -d           - set debug on. Presently ".($dbg_on ? "ON" : "OFF")."\n";
   $arg .= " -i fn        - use 'fn' as an input file, containing folders per line.\n";
   $arg .= " -max nnn     - maximum CD/DVD size, where nnn is in MB. Default = ".b2ks2($max_cd)."\n";
   $arg .= " -version     - displays version and exits\n";
   $arg .= " -s[on|off]   - Enable or disable size sorting.\n";
   $arg .= " -s[up|down]  - Enable sorting 'up', or 'down'\n";
   $arg .= " -sa[up|down] - Enable alpha sorting 'up', or 'down'\n";
   $arg .= " -v[Num}      - set verbosity level. Presently [$verbose].\n";
   $arg .= " -x <DIR>     - Exclude this directory. \@file - line separated list to exclude.\n";
   $arg .= " -xd          - Exclude sub-directories. Only root files.\n";
   $arg .= " -ll          - Load log file at end.\n";
   $arg .= " input_folder[s] - Directories to process ... recursive assumed.\n";
   $arg .= "If none given, abort operation.\n";
   prt("$arg\n");
   pgm_exit(0,'Help exit');
}

sub pre_parse_v_opt {
   my @av = @_;
   while (@av) {
      my $arg = $av[0];
      if ($arg =~ /^-v/) {
         deal_with_v_opt($arg);
      }
      shift @av;
   }
}

sub parse_arguments {
   my @av = @_; # take it off the passed stack
   my ($tmp,$len,$i,$cc);
   pre_parse_v_opt(@av);
   while (@av) {
      my $arg = $av[0];
      if ($arg eq '-version') {
         prt( "Version 0.0.1\n" );
         pgm_exit(0,'Version exit');
      } elsif (($arg eq '-?')||($arg eq '-h')||($arg eq '--help')) {
         give_help();
         pgm_exit(0,"HelpExit");
      } elsif ($arg eq '-i') {
         require_argument(@av);
         shift @av;
         $arg = $av[0];
         deal_with_i_opt($arg);
      } elsif ($arg =~ /^-v/) {
         # already done - deal_with_v_opt($arg);
      } elsif ($arg eq '-d') {
         prtv1( "Setting debug output ...\n" );
         $dbg_on = 1;
      } elsif ($arg eq '-ll') {
         $load_log = 1;
         prtv1( "Set load log file at end.\n" );
      } elsif ($arg eq '-max') {
         require_argument(@av);
         shift @av;
         $arg = $av[0];
         $max_cd = $arg * 1024 * 1024;
         prtv1( "Setting max CD/DVD to $max_cd (".b2ks2($max_cd).") ...\n" );
      } elsif ($arg =~ /^-s/) {
         deal_with_s_opt($arg);
      } elsif ($arg eq '-x') {
         require_argument(@av);
         shift @av;
         $arg = $av[0];
         deal_with_x_opt($arg);
         $got_exclude_dirs = scalar keys(%exclude_dirs);
         prtv1( "Added [$arg] to exclude directory...($got_exclude_dirs)\n" );
      } elsif ($arg eq '-xd') {
         $recursive = 0;
         prtv1( "Set recursive off. No sub-directories scanned\n" );
      } elsif ($arg =~ /^-/) {
         prt( "ERROR: unrecognised option? [$arg]! Try -? ... aborting...\n" );
         pgm_exit(1,"Bad Option");
      } else {
         prtv1( "Storing argument [$arg].\n" );
         push(@in_files, $arg);
      }
      shift @av; # move to next argument to [0]
   }

   $got_exclude_dirs = scalar keys(%exclude_dirs);
   push(@in_files, $def_file) if (!@in_files && $add_def_if_none); # default to current folder
}

# eof - dvdsizes.pl
