Index: /main/trunk/greenstone2/perllib/FileUtils.pm
===================================================================
--- /main/trunk/greenstone2/perllib/FileUtils.pm	(revision 37150)
+++ /main/trunk/greenstone2/perllib/FileUtils.pm	(revision 37151)
@@ -116,4 +116,105 @@
 
 
+## @function _copyFilesGeneral()
+#
+# internal version that copies a file or a group of files
+#
+sub _copyFilesGeneral
+{
+    my ($srcfiles_ref,$dest,$options) = @_;
+    
+    # upgrade srcfiles_ref to array reference, if what is passed in is a single (scalar) filename
+    $srcfiles_ref = [ $srcfiles_ref] if (ref $srcfiles_ref eq "");
+    
+    my $strict   = (defined $options && $options->{'strict'})   ? $options->{'strict'}   : 0;
+    my $hardlink = (defined $options && $options->{'hardlink'}) ? $options->{'hardlink'} : 0;
+    
+    # remove trailing slashes from source and destination files
+    $dest =~ s/[\\\/]+$//;
+    map {$_ =~ s/[\\\/]+$//;} @$srcfiles_ref;
+    
+    # a few sanity checks
+    if (scalar(@$srcfiles_ref) == 0)
+    {
+	print STDERR "FileUtils::_copyFilesGeneral() no destination directory given\n";
+	return 0;
+    }
+    elsif ((scalar(@$srcfiles_ref) > 1) && (!-d $dest))
+    {
+	print STDERR "FileUtils::_copyFilesGeneral() if multiple source files are given the destination must be a directory\n";
+	return 0;
+    }
+    
+    my $had_an_error = 0;
+    
+    # copy the files
+    foreach my $file (@$srcfiles_ref)
+    {
+	my $tempdest = $dest;
+	if (-d $tempdest)
+	{
+	    my ($filename) = $file =~ /([^\\\/]+)$/;
+	    $tempdest .= "/$filename";
+	}
+	if (!-e $file)
+	{
+	    print STDERR "FileUtils::_copyFilesGeneral() $file does not exist\n";
+	    $had_an_error = 1;
+	    if ($strict) {
+		return 0;
+	    }
+	}
+	elsif (!-f $file)
+	{
+	    print STDERR "FileUtils::_copyFilesGeneral() $file is not a regular file\n";
+	    $had_an_error = 1;
+	    if ($strict) {
+		return 0;
+	    }
+	}
+	else
+	{
+	    my $success = undef;
+
+	    if ($hardlink) {
+		
+		if (!link($file, $tempdest))
+		{
+		    print STDERR "Warning: FileUtils::_copyFilesGeneral(): unable to create hard link. ";
+		    print STDERR "  Attempting file copy: $file -> $tempdest\n";
+		    $success = &File::Copy::copy($file, $tempdest);
+		}
+		else {
+		    $success = 1;
+		}
+
+	    }
+	    else {
+		$success = &File::Copy::copy($file, $tempdest);
+	    }
+	    
+	    if (!$success) {
+		print STDERR "FileUtils::_copyFilesGeneral() failed to copy $file -> $tempdest\n";
+		$had_an_error = 1;
+		
+		if ($strict) {
+		    return 0;
+		}
+	    }
+	}
+    }
+    
+    if ($had_an_error) {
+	return 0;
+    }
+    else {
+	# true => everything OK
+	return 1;
+    }
+    
+}
+
+
+
 ## @function copyFiles()
 #
@@ -121,4 +222,12 @@
 #
 sub copyFiles
+{
+  my $dest = pop (@_);
+  my (@srcfiles) = @_;
+  
+  return &_copyFilesGeneral(\@srcfiles,$dest,undef);
+}
+
+sub copyFilesDEPRECATED
 {
   my $dest = pop (@_);
@@ -133,12 +242,14 @@
   {
     print STDERR "FileUtils::copyFiles() no destination directory given\n";
-    return;
-  }
-  elsif ((scalar (@srcfiles) > 1) && (!-d $dest))
+    return 0;
+  }
+  elsif ((scalar(@srcfiles) > 1) && (!-d $dest))
   {
     print STDERR "FileUtils::copyFiles() if multiple source files are given the destination must be a directory\n";
-    return;
-  }
-
+    return 0;
+  }
+
+  my $had_an_error = 0;
+  
   # copy the files
   foreach my $file (@srcfiles)
@@ -152,17 +263,89 @@
     if (!-e $file)
     {
-      print STDERR "FileUtils::copyFiles() $file does not exist\n";
+	print STDERR "FileUtils::copyFiles() $file does not exist\n";
+	$had_an_error = 1;
     }
     elsif (!-f $file)
     {
-      print STDERR "FileUtils::copyFiles() $file is not a plain file\n";
+	print STDERR "FileUtils::copyFiles() $file is not a regular file\n";
+	$had_an_error = 1;
     }
     else
     {
-      &File::Copy::copy ($file, $tempdest);
-    }
-  }
+	my $success = &File::Copy::copy ($file, $tempdest);
+	if (!$success) {
+	    $had_an_error = 1;
+	}
+    }
+  }
+
+  if ($had_an_error) {
+      return 0;
+  }
+  else {
+      # true => everything OK
+      return 1;
+  }
+
 }
 ## copyFiles()
+
+
+## @function _readdirWithOptions()
+#
+# Internal version to support public functions such as readdirFullpath and readDirectory
+
+sub _readdirWithOptions
+{
+    my ($src_dir_fullpath,$options) = @_;
+    
+    my $ret_val_success = 1; # default (true) is to assume things will work out!
+    
+    my $all_files_and_dirs = [];
+
+    my $strict = 0;
+    my $make_fullpath = 0;
+    my $exclude_filter_re = undef;
+    my $include_filter_re = undef;
+
+    if (defined $options) {
+	$strict = $options->{'strict'} if defined $options->{'strict'};
+	$make_fullpath = $options->{'make_fullpath'} if defined $options->{'make_fullpath'};
+	$exclude_filter_re = $options->{'exclude_filter_re'} if defined $options->{'exclude_filter_re'};
+	$include_filter_re = $options->{'include_filter_re'} if defined $options->{'include_filter_re'};
+    }
+
+    # get the contents of this directory
+    if (!opendir(INDIR, $src_dir_fullpath))
+    {
+	print STDERR "FileUtils::readdirFullpath() could not open directory $src_dir_fullpath\n";
+	$ret_val_success = 0;	
+    }
+    else
+    {
+	my @next_files_and_dirs = readdir(INDIR);
+	closedir (INDIR);
+
+	foreach my $f_or_d (@next_files_and_dirs)
+	{
+	    next if $f_or_d =~ /^\.\.?$/;
+	    next if (defined $exclude_filter_re && ($f_or_d =~ m/$exclude_filter_re/));
+	    
+	    if ((!defined $include_filter_re) || ($f_or_d =~ m/$include_filter_re/)) {
+		if ($make_fullpath) {
+		    my $ff_or_dd = &filenameConcatenate($src_dir_fullpath, $f_or_d);
+		    push(@$all_files_and_dirs,$ff_or_dd);
+		}
+		else {
+		    push(@$all_files_and_dirs,$f_or_d);
+		}
+	    }
+	}
+
+    }
+
+    return ($ret_val_success,$all_files_and_dirs);
+}
+
 
 
@@ -178,6 +361,20 @@
 {
     my ($src_dir_fullpath,$options) = @_;
-
-    my $ret_val = 1; # assume things will work out!
+    
+    my $topped_up_options = { %$options };
+    
+    $topped_up_options->{'make_fullpath'} = 1;
+    
+    my ($ret_val_success,$fullpath_files_and_dirs) = _readdirWithOptions($src_dir_fullpath,$topped_up_options);
+
+    return ($ret_val_success,$fullpath_files_and_dirs);
+}
+
+sub readdirFullpathDEPRECATED
+{
+    my ($src_dir_fullpath,$options) = @_;
+    
+    my $ret_val_success = 1; # default (true) is to assume things will work out!
+    
     my $fullpath_files_and_dirs = [];
 
@@ -193,5 +390,5 @@
     {
 	print STDERR "FileUtils::readdirFullpath() could not open directory $src_dir_fullpath\n";
-	$ret_val = 0;	
+	$ret_val_success = 0;	
     }
     else
@@ -213,5 +410,5 @@
     }
 
-    return ($ret_val,$fullpath_files_and_dirs);
+    return ($ret_val_success,$fullpath_files_and_dirs);
 }
 
@@ -222,8 +419,21 @@
 # internal support routine for recursively copying or hard-linking files
 #
+# Notes that the src-files are passed as a reference, and so a single arguemnt,
+# whereas the the public facing functions take a array or arguments, and pops off the
+# final entry and treats it as the 'dest' 
+
 sub _copyFilesRecursiveGeneral
 {
     my ($srcfiles_ref,$dest,$depth,$options) = @_;
 
+    # upgrade srcfiles_ref to array reference, if what is passed in is a single (scalar) filename
+    $srcfiles_ref = [ $srcfiles_ref] if (ref $srcfiles_ref eq "");
+        
+    # 'strict' defaults to false
+    # when false, this means, in situations where it can, even if an error is encountered it keeps going
+    my $strict   = (defined $options && $options->{'strict'})   ? $options->{'strict'}   : 0;
+    my $hardlink = (defined $options && $options->{'hardlink'}) ? $options->{'hardlink'} : 0;
+    my $copytype = (defined $options && $options->{'copytype'}) ? $options->{'copytype'} : "recursive";
+    
     # a few sanity checks
     my $num_src_files = scalar (@$srcfiles_ref);
@@ -231,10 +441,10 @@
     if ($num_src_files == 0)
     {
-	print STDERR "FileUtils::copyFilesRecursive() no destination directory given\n";
+	print STDERR "FileUtils::_copyFilesRecursiveGeneral() no destination directory given\n";
 	return 0;
     }
     elsif (-f $dest)
     {
-	print STDERR "FileUtils::copyFilesRecursive() destination must be a directory\n";
+	print STDERR "FileUtils::_copyFilesRecursiveGeneral() destination must be a directory\n";
 	return 0;
     }
@@ -292,4 +502,5 @@
     }
 
+    my $had_an_error = 0;	
     
     # copy the files
@@ -299,10 +510,17 @@
 	{
 	    print STDERR "FileUtils::_copyFilesRecursiveGeneral() $file does not exist\n";
-	    # wrap up in strict option check
-	    return 0;
+	    
+	    if ($strict) {
+		return 0;
+	    }
+	    else {
+		$had_an_error = 1;
+	    }
 	}
 	elsif (-d $file)
 	{
-	    my $src_dir_fullpath = $file; # know by this point that $file is actually a sub-directory
+	    # src-file is a diretory => recursive case
+	    
+	    my $src_dir_fullpath = $file; 
 
 	    # make the new directory
@@ -310,60 +528,82 @@
 
 	    my $next_dest = &filenameConcatenate($dest, $src_dirname_tail);
+
 	    my $store_umask = umask(0002);
-	    mkdir ($next_dest, 0777);
+	    my $mkdir_success_ok = mkdir($next_dest, 0777);
 	    umask($store_umask);
 
+	    if (!$mkdir_success_ok) {
+		$had_an_error = 1;
+		if ($strict) {
+		    return 0;
+		}
+	    }
+	    
 	    my ($readdir_status, $fullpath_src_subfiles_and_subdirs) = &readdirFullpath($src_dir_fullpath,$options);
 
 	    if (!$readdir_status) {
-		return 0;
+		$had_an_error = 1;
+		if ($strict) {
+		    return 0;
+		}
 	    }
 	    else {
 
-		foreach my $fullpath_subf_or_subd (@$fullpath_src_subfiles_and_subdirs)
-		{
-		    # Recursively copy all the files/dirs in this directory:
-		    #   In the general version need the source argument to be a reference to an array
-		    my $ret_val = &_copyFilesRecursiveGeneral([$fullpath_subf_or_subd],$next_dest, $depth+1, $options);
-
-		    if ($ret_val == 0) {
-			# Error condition encountered
-			return 0;
+		if ($copytype eq "toplevel") {
+		    foreach my $fullpath_subf_or_subd (@$fullpath_src_subfiles_and_subdirs)
+		    {
+			if (-f $fullpath_subf_or_subd)
+			{
+			    my $fullpath_subf = $fullpath_subf_or_subd;
+			    my $ret_val_success = &_copyFilesGeneral([$fullpath_subf],$dest,$options);
+
+			    if ($ret_val_success == 0) {
+
+				$had_an_error = 1;
+				if ($strict) {
+				    return 0;
+				}
+			    }
+			}
+			
 		    }
 		}
-	    }
-		
-#	    # get the contents of this directory
-#	    if (!opendir(INDIR, $src_dir_fullpath))
-#	    {
-#		print STDERR "FileUtils::_copyFilesRecursiveGeneral() could not open directory $src_dir_fullpath\n";
-#	    }
-#	    else
-#	    {
-#		my @next_files_and_dirs = readdir(INDIR);
-#		closedir (INDIR);
-#		foreach my $f_or_d (@next_files_and_dirs)
-#		{
-#		    next if $f_or_d =~ /^\.\.?$/;
-#		    # recursively copy all the files/dirs in this directory
-#		    my $ff_or_dd = &filenameConcatenate($src_dir_fullpath, $f_or_d);
-#		    # In the general version need the source argument to be a reference to an array
-#		    my $ret_val = &_copyFilesRecursiveGeneral($next_dest, [ $ff_or_dd ], $options);
-#
-#		    if ($ret_val == 0) {
-#			# Error condition encountered
-#			return 0;
-#		    }
-#		}
-#	    }
-	    
+		else {			
+		    # Recursively copy all the files/dirs in this directory:
+		    my $ret_val_success = &_copyFilesRecursiveGeneral($fullpath_src_subfiles_and_subdirs,$next_dest, $depth+1, $options);
+		    
+		    if ($ret_val_success == 0) {
+			
+			$had_an_error = 1;
+			if ($strict) {
+			    return 0;
+			}
+		    }		    
+		}
+	    }		
 	}
 	else
 	{
-	    &copyFiles($file, $dest);
+	    my $ret_val_success = &_copyFilesGeneral([$file], $dest, $options);
+	    if ($ret_val_success == 0) {
+
+		$had_an_error = 1;
+		if ($strict) {
+		    # Error condition encountered in copy => immediately bail, passing the error on to outer calling function
+		    return 0;
+		}
+	    }
 	}
     }
 
-    return 1;
+    # get to here, then everything went well
+
+    if ($had_an_error) {
+	return 0;
+    }
+    else {
+	# true => everything OK
+	return 1;
+    }
 }
 ## _copyFilesRecursiveGeneral()
@@ -378,4 +618,12 @@
 #
 sub copyFilesRecursive
+{
+  my $dest = pop (@_);
+  my (@srcfiles) = @_;
+
+  return _copyFilesRecursiveGeneral(\@srcfiles,$dest,0,undef);
+}
+
+sub copyFilesRecursiveDEPRECATED
 {
   my $dest = pop (@_);
@@ -433,5 +681,5 @@
           # copy all the files in this directory
           my $ff = &filenameConcatenate($file, $f);
-          &copyFilesRecursive($ff, $dest);
+          &copyFilesRecursiveDEPRECATED($ff ,$dest);
         }
       }
@@ -457,4 +705,12 @@
 #
 sub copyFilesRecursiveNoSVN
+{
+  my $dest = pop (@_);
+  my (@srcfiles) = @_;
+
+  return _copyFilesRecursiveGeneral(\@srcfiles,$dest, 0, { 'exclude_filter_re' => "^\\.svn\$" } );
+}
+
+sub copyFilesRecursiveNoSVNDEPRECATED
 {
   my $dest = pop (@_);
@@ -513,5 +769,5 @@
           my $ff = &filenameConcatenate($file, $f);
           # util.pm version incorrectly called cp_r here - jmt12
-          &copyFilesRecursiveNoSVN($ff, $dest);
+          &copyFilesRecursiveNoSVNDEPRECATED($ff ,$dest);
         }
       }
@@ -533,4 +789,12 @@
 #
 sub copyFilesRecursiveTopLevel
+{
+  my $dest = pop (@_);
+  my (@srcfiles) = @_;
+
+  return _copyFilesRecursiveGeneral(\@srcfiles,$dest, 0, { 'copytype' => "toplevel" } );
+}
+
+sub copyFilesRecursiveTopLevelDEPRECATED
 {
   my $dest = pop (@_);
@@ -605,4 +869,34 @@
 
 
+## @function hardlinkFilesRecursive()
+#
+# recursively hard-links a file or group of files syntax similar to
+# how 'cp -r' operates (only hard-linking of course!)
+# (sourcefiles, destination directory) destination must be a directory
+# to copy one file to another use cp instead
+#
+
+sub hardlinkFilesRefRecursive
+{
+    my ($srcfiles_ref,$dest, $options) = @_;
+
+    # only dealing with scalar values in 'options' so OK to shallow copy
+    my $options_clone = (defined $options) ? { %$options } : {};
+
+    # top-up with setting to trigger hard-linking
+    $options_clone->{'hardlink'} = 1;
+    
+    _copyFilesRecursiveGeneral($srcfiles_ref,$dest,0, $options_clone);
+}
+
+sub hardlinkFilesRecursive
+{
+    my $dest = pop (@_);
+    my (@srcfiles) = @_;
+
+    _copyFilesRecursiveGeneral(\@srcfiles,$dest,0, { 'hardlink' => 1 });
+}
+
+
 ## @function differentFiles()
 #
@@ -823,26 +1117,51 @@
 sub hardLink
 {
-  my ($src, $dest, $verbosity) = @_;
-
+  my ($src, $dest, $verbosity, $options) = @_;
+
+  # 'strict' defaults to false
+  # see _copyFilesRecursiveGeneral for more details
+  my $strict = (defined $options && $options->{'strict'}) ? $options->{'strict'} : 0;
+      
   # remove trailing slashes from source and destination files
   $src =~ s/[\\\/]+$//;
   $dest =~ s/[\\\/]+$//;
 
+  my $had_an_error = 0;
+  
   ##    print STDERR "**** src = ", unicode::debug_unicode_string($src),"\n";
   # a few sanity checks
   if (!-e $src)
   {
-    print STDERR "FileUtils::hardLink() source file \"" . $src . "\" does not exist\n";
-    return 1;
+      print STDERR "FileUtils::hardLink() source file \"" . $src . "\" does not exist\n";
+      if ($strict) {
+	  return 0;
+      }
+      else {
+	  $had_an_error = 1;
+      }
   }
   elsif (-d $src)
   {
-    print STDERR "FileUtils::hardLink() source \"" . $src . "\" is a directory\n";
-    return 1;
+      print STDERR "FileUtils::hardLink() source \"" . $src . "\" is a directory\n";
+      if ($strict) {
+	  return 0;
+      }
+      else {
+	  $had_an_error = 1;
+      }
   }
   elsif (-e $dest)
   {
-      print STDERR "FileUtils::hardlink() dest file ($dest) exists, removing it\n";
-      &removeFiles($dest);
+      if ($strict) {
+	  return 0;
+      }
+      else {
+	  print STDERR "FileUtils::hardLink() dest file ($dest) exists, removing it\n";
+	  my $status_ok = &removeFiles($dest);
+
+	  if (!$status_ok) {
+	      $had_an_error = 1;
+	  }
+      }
   }
 
@@ -850,5 +1169,11 @@
   if (!-e $dest_dir)
   {
-    &makeAllDirectories($dest_dir);
+      my $status_ok = &makeAllDirectories($dest_dir);
+      if ($strict) {
+	  return 0;
+      }
+      else {
+	  $had_an_error = 1;
+      }
   }
 
@@ -857,10 +1182,20 @@
     if ((!defined $verbosity) || ($verbosity>2))
     {
-      print STDERR "FileUtils::hardLink(): unable to create hard link. ";
-      print STDERR " Copying file: $src -> $dest\n";
-    }
-    &File::Copy::copy ($src, $dest);
-  }
-  return 0;
+      print STDERR "Warning: FileUtils::hardLink(): unable to create hard link. ";
+      print STDERR "  Copying file: $src -> $dest\n";
+    }
+    my $status_ok = &File::Copy::copy($src, $dest);
+    if (!$status_ok) {
+	$had_an_error = 1;
+    }
+  }
+
+  if ($had_an_error) {
+      return 0;
+  }
+  else {
+      # no fatal issue encountered => return true
+      return 1;
+  }
 }
 ## hardLink()
@@ -922,6 +1257,5 @@
   my ($dir) = @_;
 
-  # use / for the directory separator, remove duplicate and
-  # trailing slashes
+  # use / for the directory separator, remove duplicate and trailing slashes
   $dir=~s/[\\\/]+/\//g;
   $dir=~s/[\\\/]+$//;
@@ -946,5 +1280,5 @@
       {
         print STDERR "FileUtils::makeAllDirectories() could not create directory $dirsofar\n";
-        return;
+        return 0;
       }
     }
@@ -967,6 +1301,9 @@
   {
     print STDERR "FileUtils::makeDirectory() could not create directory $dir\n";
-    return;
-  }
+    return 0;
+  }
+
+  # get to here, everything went as expected
+  return 1;
 }
 ## makeDirectory()
@@ -991,4 +1328,10 @@
 sub moveDirectoryContents
 {
+    # Currently has no return values!!!
+    
+    #### !!!! worthy of upgrading to include $options, and then use
+    #### !!!! 'strict' to determine whether it returns 0 when hitting
+    #### !!!! an issue immediately, or else persevere, and continue
+    
   my ($src_dir, $dest_dir) = @_;
 
@@ -1073,12 +1416,14 @@
   {
     print STDERR "FileUtils::moveFiles() no destination directory given\n";
-    return;
+    return 0;
   }
   elsif ((scalar (@srcfiles) > 1) && (!-d $dest))
   {
     print STDERR "FileUtils::moveFiles() if multiple source files are given the destination must be a directory\n";
-    return;
-  }
-
+    return 0;
+  }
+
+  my $had_an_error = 0;
+  
   # move the files
   foreach my $file (@srcfiles)
@@ -1092,19 +1437,28 @@
     if (!-e $file)
     {
-      print STDERR "FileUtils::moveFiles() $file does not exist\n";
+	print STDERR "FileUtils::moveFiles() $file does not exist\n";
+	$had_an_error = 1;
     }
     else
     {
-      if(!rename ($file, $tempdest))
+      if (!rename($file, $tempdest))
       {
-        print STDERR "**** Failed to rename $file to $tempdest\n";
-        &File::Copy::copy($file, $tempdest);
-        &removeFiles($file);
+        print STDERR "**** Failed to rename $file to $tempdest.  Attempting copy and then delete\n";
+        my $copy_status_ok = &File::Copy::copy($file, $tempdest);
+	if ($copy_status_ok) {
+	    my $remove_status_ok = &removeFiles($file);
+	    if (!$remove_status_ok) {
+		$had_an_error = 1;
+	    }
+	}
+	else {
+	    $had_an_error = 1;
+	}
       }
       # rename (partially) succeeded) but srcfile still exists after rename
-      elsif(-e $file)
+      elsif (-e $file)
       {
         #print STDERR "*** srcfile $file still exists after rename to $tempdest\n";
-        if(!-e $tempdest)
+        if (!-e $tempdest)
         {
           print STDERR "@@@@ ERROR: $tempdest does not exist\n";
@@ -1112,11 +1466,21 @@
         # Sometimes the rename operation fails (as does
         # File::Copy::move).  This turns out to be because the files
-        # are hardlinked.  Need to do a copy-delete in this case,
+        # are hard-linked.  Need to do a copy-delete in this case,
         # however, the copy step is not necessary: the srcfile got
         # renamed into tempdest, but srcfile itself still exists,
         # delete it.  &File::Copy::copy($file, $tempdest);
-        &removeFiles($file);
-      }
-    }
+        my $remove_status_ok = &removeFiles($file);
+	if (!$remove_status_ok) {
+	    $had_an_error = 1;
+	}
+      }
+    }
+  }
+
+  if ($had_an_error) {
+      return 0;
+  }
+  else {
+      return 1;
   }
 }
@@ -1156,7 +1520,24 @@
 
 
+
 ## @function readDirectory()
 #
 sub readDirectory
+{
+    my $path = shift(@_);
+    
+    my $options = { 'strict' => 1 };
+    
+    my ($ret_val_success,$files_and_dirs) = _readdirWithOptions($path,$options);
+    
+    if (!$ret_val_success) {
+	die("Error! Failed to list files in directory: " . $path . "\n");
+    }
+    
+    return $files_and_dirs;
+}
+
+
+sub readDirectoryDEPRECATED
 {
   my $path = shift(@_);
@@ -1169,9 +1550,31 @@
   else
   {
-    die("Error! Failed to open directory to list files: " . $path . "\n");
+    die("Error! Failed to open directory list files: " . $path . "\n");
   }
   return \@files;
 }
 ## readDirectory()
+
+## @function readDirectoryFiltered()
+#
+sub readDirectoryFiltered
+{
+    my ($path,$exclude_filter_re,$include_filter_re) = @_;
+    
+    my $options = { 'strict' => 1 };
+
+    $options->{'exclude_filter_re'} = $exclude_filter_re if defined $exclude_filter_re;
+    $options->{'include_filter_re'} = $include_filter_re if defined $include_filter_re;
+    
+    my ($ret_val_success,$files_and_dirs) = _readdirWithOptions($path,$options);
+    
+    if (!$ret_val_success) {
+	die("Error! Failed to list files in directory: " . $path . "\n");
+    }
+    
+    return $files_and_dirs;
+}
+
+## readDirectoryFiltered()
 
 ## @function readUTF8File()
@@ -1239,4 +1642,6 @@
   my @filefiles = ();
 
+  my $ret_val_success = 1; # default (true) is to assume everything works out
+  
   # make sure the files we want to delete exist
   # and are regular files
@@ -1245,9 +1650,9 @@
     if (!-e $file)
     {
-      print STDERR "FileUtils::removeFiles() $file does not exist\n";
+	print STDERR "Warning: FileUtils::removeFiles() $file does not exist\n";
     }
     elsif ((!-f $file) && (!-l $file))
     {
-      print STDERR "FileUtils::removeFiles() $file is not a regular (or symbolic) file\n";
+      print STDERR "Warning: FileUtils::removeFiles() $file is not a regular (or symbolic) file\n";
     }
     else
@@ -1261,8 +1666,16 @@
 
   # check to make sure all of them were removed
-  if ($numremoved != scalar(@filefiles))
-  {
-    print STDERR "FileUtils::removeFiles() Not all files were removed\n";
-  }
+  if ($numremoved != scalar(@filefiles)) {
+      print STDERR "FileUtils::removeFiles() Not all files were removed\n";
+
+      if ($numremoved == 0) {
+	  # without a '$options' parameter to provide strict=true/false then
+	  # interpret this particular situation as a "major" fail
+	  # => asked to remove files and not a single one was removed!
+	  $ret_val_success = 0;
+      }
+  }
+
+  return $ret_val_success;
 }
 ## removeFiles()
@@ -1308,6 +1721,10 @@
 sub removeFilesFiltered
 {
-  my ($files,$file_accept_re,$file_reject_re) = @_;
-
+  my ($files,$file_accept_re,$file_reject_re, $options) = @_;
+
+  # 'strict' defaults to false
+  # see _copyFilesRecursiveGeneral for more details
+  my $strict = (defined $options && $options->{'strict'}) ? $options->{'strict'} : 0;
+      
   #   my ($cpackage,$cfilename,$cline,$csubr,$chas_args,$cwantarray) = caller(2);
   #   my ($lcfilename) = ($cfilename =~ m/([^\\\/]*)$/);
@@ -1316,4 +1733,6 @@
   my @files_array = (ref $files eq "ARRAY") ? @$files : ($files);
 
+  my $had_an_error = 0;
+  
   # recursively remove the files
   foreach my $file (@files_array)
@@ -1323,13 +1742,18 @@
     if (!-e $file)
     {
-      print STDERR "FileUtils::removeFilesFiltered() $file does not exist\n";
+	# handle this as a warning rather than a fatal error that stops deleting files/dirs
+	print STDERR "FileUtils::removeFilesFiltered() $file does not exist\n";
+	$had_an_error = 1;
+	last if ($strict);
     }
     # don't recurse down symbolic link
     elsif ((-d $file) && (!-l $file))
     {
-      # get the contents of this directory
+      # specified '$file' is a directory => get the contents of this directory
       if (!opendir (INDIR, $file))
       {
-        print STDERR "FileUtils::removeFilesFiltered() could not open directory $file\n";
+	  print STDERR "FileUtils::removeFilesFiltered() could not open directory $file\n";
+	  $had_an_error = 1;
+	  last;
       }
       else
@@ -1340,26 +1764,51 @@
         # remove all the files in this directory
         map {$_="$file/$_";} @filedir;
-        &removeFilesFiltered(\@filedir,$file_accept_re,$file_reject_re);
-
-        if (!defined $file_accept_re && !defined $file_reject_re)
-        {
-          # remove this directory
-          if (!rmdir $file)
-          {
-            print STDERR "FileUtils::removeFilesFiltered() couldn't remove directory $file\n";
-          }
+        my $remove_success_ok = &removeFilesFiltered(\@filedir,$file_accept_re,$file_reject_re);
+
+	if ($remove_success_ok) {
+	    if (!defined $file_accept_re && !defined $file_reject_re)
+	    {		
+		# no filters were in effect, and all files were removed
+		# => remove this directory
+		if (!rmdir $file)
+		{
+		    print STDERR "FileUtils::removeFilesFiltered() couldn't remove directory $file\n";
+
+		    $had_an_error = 1; # back to there being a problem
+		    last if ($strict);
+		}
+	    }
         }
+	else {
+	    # had a problems in the above 
+	    $had_an_error = 1;
+	    last if ($strict);
+	}
       }
     }
     else
     {
-      next if (defined $file_reject_re && ($file =~ m/$file_reject_re/));
-
-      if ((!defined $file_accept_re) || ($file =~ m/$file_accept_re/))
-      {
-        # remove this file
-        &removeFiles($file);
-      }
-    }
+	# File exists => skip if it matches the file_reject_re
+	
+	next if (defined $file_reject_re && ($file =~ m/$file_reject_re/));
+
+	if ((!defined $file_accept_re) || ($file =~ m/$file_accept_re/))
+	{
+	    # remove this file
+	    my $remove_success_ok = &removeFiles($file);
+
+	    if (!$remove_success_ok) {
+		$had_an_error = 1;
+		last if ($strict);
+	    }
+	}
+    }
+  }
+
+  if ($had_an_error) {
+      return 0;
+  }
+  else {
+      return 1;
   }
 }
@@ -1376,5 +1825,5 @@
   # use the more general (but reterospectively written) function
   # filtered_rm_r function() with no accept or reject expressions
-  &removeFilesFiltered(\@files,undef,undef);
+  return &removeFilesFiltered(\@files,undef,undef);
 }
 ## removeFilesRecursive()
