#!/usr/bin/perl
############################################################################
#
# Creates make.files - a list of all source files
#
############################################################################

#
# main - top level code
#

if ( @ARGV ) {                # parse command line args
    print "usage: perl mkfiles.pl\n\n";
    exit 1;
}

$tolower = 0;  #Do we want to convert items in make.files to lower case?
$verbose = 1;  #Do we want to list the files?



print "###########################\n";
print "## Generating make.files ##\n";
print "###########################\n";

&doMakeFiles();  #Do your magic!

print "###########################\n";
print "## make.files   done     ##\n";
print "###########################\n";

exit 0;



############################################################################
#
# Main routine.  Read make.exclude,  then search the current directory
# recursively for source code items, rejecting those listed in make.exclude
#
############################################################################
sub doMakeFiles
{
    my $excludes;   #list of files to exclude
    my @excluded;   #list of files that were actually excluded
    my @irrelevant; #list of files in make.exclude that were not found
    my $line;       #current line from make.exclude
    my $patterns;   #The extensions for which to search
    my @files;      #Result of find_files()
    my @codefiles;  #Sorted list of @files
    my $datestr;    #Current date
    local(*MAKE_DOT_EXCLUDE);
    local(*MAKE_DOT_FILES);

    if ( -r "make.exclude" )
        {
        open MAKE_DOT_EXCLUDE, "make.exclude" or
            die "make.exclude: $!";
        while (<MAKE_DOT_EXCLUDE>)
            {
            $line = $_;
            #Trim whitespace from ends
            $line =~ s/^\s|\t|\n//;
            #Ignore if no text in line
            next if ( length($line) < 1 );
            #Ignore if starts with '#'
            next if ( $line =~ /^#/ );
            # print $line, "\n";
            $excludes->{$line} = 1;
            }
        close MAKE_DOT_EXCLUDE;
        }
    
    #while ( my ($key, $value) = each(%{$excludes}) )
    #    {
    #    print "$key => $value\n";
    #    }
    
    $patterns = '.c$|.cpp$|.h$|.hpp$';
    
    @files = &find_files(".", $patterns, $excludes, \@excluded);
    
    # Print the list of files excluded
    print "###EXCLUDED: ", scalar(@excluded), " files/directories rejected by request\n";
    @excluded = sort(@excluded);
    foreach (@excluded)
        {
        if ($verbose)
          {
          print "    $_\n";
          }
        #mark the item in the hash table , so we know it occurred
        $excludes->{$_} = 0;
        }

    # Count how many files in make.exclude were not used
    foreach (keys(%{$excludes}))
        {
        #if still a 1, then it was not used
        if ($excludes->{$_} !=0)
            {
            push @irrelevant, $_;
            }
        }
 
    # Print the list of file in make.exclude, but not used.
    if (scalar(@irrelevant)>0)
        {
        @irrelevant = sort(@irrelevant);
        print "###IRRELEVANT: ", scalar(@irrelevant), " entries in make.exclude that were not found\n";
        foreach (@irrelevant)
            {
            if ($verbose)
              {
              print "    $_\n";
              }
            }
        }

    @codefiles = sort(@files);
    
    $datestr = gmtime();
    open MAKE_DOT_FILES, ">make.files" or
        die("make.files: $!");
    print MAKE_DOT_FILES "########################################################\n";
    print MAKE_DOT_FILES "## File: make.files\n";
    print MAKE_DOT_FILES "## Purpose: Used by mkdep.pl\n";
    print MAKE_DOT_FILES "## Generated by mkfiles.pl at :$datestr\n";
    print MAKE_DOT_FILES "########################################################\n\n";
    foreach (@codefiles)
        {
        next if (length($_)<1);
        print MAKE_DOT_FILES "$_\n";
        }
    close MAKE_DOT_FILES;
    
} # doMakeFiles
    



############################################################################
#
# Search the current directory recursively,  checking rejecting items from
# make.exclude, or adding those that match the extensions in $patterns.
# @param $dir      the current directory being searched
# @param $patterns the file extensions for which we are searching
# @param $excludes a hash of the files which should be rejected
# @param $excluded an array in which to store a record of all files rejected
#
############################################################################
sub find_files
{
    my($dir, $patterns, $excludes, $excluded) = @_;
    my $file;
    my $p;
    my @files = ();
    my @file_result;
    local(*DIR);
    
    
    $dir =~ s=\\=/=g;
    
    # Check for 0-length
    if (length($dir)<1)
        {
        $dir = '.';
        }
    
    # Process a directory of files
    if ( opendir(DIR,$dir) )
        {
        # Remove leading .
        if ( $dir eq '.' )
            {
            $dir = '';
            }

        foreach $file ( readdir(DIR) )
            {
            # Don't allow '..'
            next if ( $file  =~ /^\.\.?$/ );
            next if ( length($file)<1 );

            if (length($dir)>0)
                {
                $p = $dir . '/' . $file;
                }
            else
                {
                $p = $file;
                }
                
            if ($tolower != 0)
                {
                $p = lc($p);
                }

            #print "File:$p\n";
            
            # Check if it is an excluded file
            if (defined($excludes->{$p}))
                {
                #print "EXCLUDED:$p\n";
                push @{$excluded}, $p;
                next;
                }
            # Check for a desired extension
            if ($p =~ /$patterns/i)
                {
                #print "match:$p\n";
                push @files, $p;
                next;
                }
             #We have seen '0' inserted from a null result.  This
             #should avoid this problem
             @file_result = &find_files($p, $patterns, $excludes, $excluded);
             if (scalar(@file_result)>0)
                 {
                 push @files, @file_result;
                 }
             }
        closedir(DIR);
        }
    return @files;
}
