#!/usr/bin/perl

# Currently, we implement only the directory option
# The following features have been requested for
#
# 1. Get the name of the directory and produce a 
#    statistic for all the files which have been touched
#    in all the subdirectories starting from that 
#    directory
#
# 2. Since gcov spits out a statistic for all the header
#    files included by all the source files, we need to 
#    aggregate them somehow into a single file. This might
#    have to be done manually by going through all the lines
#    which have been executed in that file since a header 
#    file may have multiple inclusions meaning that they
#    might have multiple .gcov files in different directories
#
# 3. Support command line parsing of arguments
#
# 4. Support giving a listing of all the files which have
#    been covered less than a certain percentage, say for
#    eg., all files which have been covered less that 5%
#

use strict;
use Switch;

#global variables
my $index = 0;
my $num_args = scalar(@ARGV);
my $percentage = 0.0;
my $ret1 = 0;
my $ret2 = 0;
my $dir_list_given = 0;
my $req_list_given = 0;

$ret1 = open(DIR_FILE, "> dir_list.txt");
$ret2 = open(REQ_FILE, "> req_list.txt");

if ($ret1 < 0 || $ret2 < 0) {
    print "ERROR: opening dir_list.txt or req_list.txt\n";
    exit(3);
}

# check the error condition
if (0 == ($num_args % 2)) {
} else {
    print "ERROR: the number of arguments has to be even\n";
    exit(3);
}

# process the arguments
while($num_args > 0) {
    switch ($ARGV[$index]) {
        case "-d" { 
           print DIR_FILE $ARGV[$index+1];
           $index += 2;
           $num_args -= 2;   
           $dir_list_given = 1;
        }
        case "-f" { 
           my $filename = `find . -name $ARGV[$index+1]`;
           print REQ_FILE $filename;
           $index += 2;
           $num_args -= 2;   
           $req_list_given = 1;
        }
        case "-p" { 
           $percentage = $ARGV[$index];
           $index += 2;
           $num_args -= 2;   
        }
        else { 
            print "ERROR: Incorrect command line option\n";
            exit(3);
        }
    }
}

close(DIR_FILE);
close(REQ_FILE);

# when nothing is specified, everything defaults to just "src"
if (0 == $dir_list_given && 0 == $req_list_given) {
    print "WARN: No directory or file has been requested\ndefaulting to src directory\n";
    system("echo src > dir_list.txt");
    $dir_list_given = 1;
}

#Now, we have both the requested file list and the directory list
#So simply call the procedure generate_stats with the required arguments
if (1 == $dir_list_given) {
    get_file_list("./dir_list.txt",
                  "touched_files.txt",
                  "untouched_files.txt");
                  
    generate_stats("touched_files.txt", # file_list
                   "coverage_stats.txt",# generic coverage numbers
                   "percent_stats.txt", # files below a certain %
                   $percentage,         # percentage below which we report
                   1);                  # 1 to report
}
               
if (1 == $req_list_given) {
    generate_stats("req_list.txt", # file_list
                   "req_stats.txt",# generic coverage
                   "",             # no percentage coverage required
                   0,              # not required
                   0);             # 0 to not report percentages
}

sub get_file_list {
    my ($input, $touched, $untouched) = @_;
    my $ret = open(DIRFILES, "< $input");
    if ($ret < 0) {
        print "ERROR: could not open directory listing\n";
        exit(3);
    }

    while(<DIRFILES>) {
        chomp();
        my $c_files = `find $_ -name \"*.c\"`;
        my $cc_files = `find $_ -name \"*.cc\"`;
        $cc_files =~ s/\.cc//g;
        $c_files =~ s/\.c//g;
        $c_files = $c_files . $cc_files;
        my @C_FILES = split(/\n/, $c_files);
        
        my $da_files = `find $_ -name \"*.da\"`;
        $da_files =~ s/\.da//g;
        my @DA_FILES = split(/\n/, $da_files);
 
        open (TEMP1, "> temp1");
        open (TEMP2, "> temp2");
        print TEMP1 $c_files;
        print TEMP2 $da_files;
        close(TEMP1);
        close(TEMP2);
 
        # Now do the manual diff 
        open(TEMP1, "< temp1");
        open(UNTOUCHED_FILES, ">> $untouched");
        open(TOUCHED_FILES, ">> $touched");
 
        while(<TEMP1>) {
            my $c_file = $_;
            my $found = 0;
            open(TEMP2, "< temp2");
            while(<TEMP2>) {
                if ($c_file eq $_) {
                    $found = 1;
                }
            }
            close(TEMP2);
            if ($found == 0) {
                print UNTOUCHED_FILES $c_file;
            } else {
                chomp($c_file);
                $c_file = $c_file . ".c\n";
               print TOUCHED_FILES $c_file;
            }
        }
        close(UNTOUCHED_FILES);
        close(TOUCHED_FILES);
        close(TEMP1);
        system("rm temp1 temp2");
    }
    close(DIRFILES);
    #Now to print the stats of all the files which are touched
    system("sort $touched -o temp; uniq temp $touched");
    system("sort $untouched -o temp; uniq temp $untouched");
}
    

# This is the function which generates the statistics and dumps it out
# to a file. Details are pretty straightforward at this point
sub generate_stats {
    my ($input_file, $coverage_file, $percent_file, $percentage, $calculate) = @_;
    my $k = 0;
    my $l = 0;

    open (INPUT, "< $input_file"); 
    open (COVERAGE, "> $coverage_file");
    if ($calculate == 1) {
        open (PERCENT, "> percent_coverage.txt");
    }

    print COVERAGE "#Index                             Filename                          Directory                 Usage(%)\n";
    print COVERAGE "#======================================================================================================\n";
    
    if ($calculate == 1) {
        print PERCENT "#Index                             Filename                          Directory                 Usage(%)\n";
        print PERCENT "#======================================================================================================\n";
    }

    my $average = 0.0;
    my $num_files = `wc -l touched_files.txt`;

    while (<INPUT>) {
        #generate the gcov file for this particular file
        #1. Get the directory name and filename seperately
        #2. Invoke gcov on the file
        #3. Print the statistic onto a file
    
        chomp();
        my $full_name = $_;
        my $file_name = `basename $full_name`;
        my $dir_name = `dirname $full_name`;
        chomp($dir_name);
        chomp($file_name);

        open(RESULT, "cd $dir_name; gcov $file_name 2> /dev/null |");
        while (<RESULT>) {
            if (/Creating/) {} 
            else  {
                #Now we are doing the right line. Search for this file
                if (/$file_name/) {
                    s/^([\s,0-9]*\.[0-9]+\%)\.*/$1/;
                    my $val = $1; 
                    $average += $val;
                    $k++;
                    my $print_string = sprintf("%4d   %40s %40s       %3.2f\n", $k, $file_name, $dir_name, $val);
                    if ($calculate == 1) {
                        if ($val <= $percentage) { 
                            $l++;
                            my $zero_string = sprintf("%4d   %40s %40s       %3.2f\n", $l, $file_name, $dir_name, $val);
                            print PERCENT $zero_string;
                        }
                    }
                    print COVERAGE $print_string;
                }
            } 
        }
        close(RESULT);
    }
    if ($num_files != 0){
        print COVERAGE "==============================================================\n";
        print COVERAGE "Average coverage was: ", $average/$num_files, "  \n";
        print COVERAGE "==============================================================\n";
    }
    close(INPUT);
    close(COVERAGE);
    if ($calculate == 1) {
        close(PERCENT);
    }
}