#!/usr/bin/perl
#

# #  Mike Ward  mward@cs.utah.edu
# #  CGI Statistics Script for Time entries for entire class
# # ---------------------------------------------------------------------
# 
# &readStuff;
# 
# $data_file_path = $stuff{'data_file_path'};
# 
# print "Content-type: text/html\n\n";
# 
# print "<HTML>\n";
# 
# print "<HEAD><TITLE>Project plan data for $stuff{'course'}\n";
# print "</TITLE></HEAD>\n";
# print "<BODY BGCOLOR=\"white\">\n";
# print "<h1 align=center>Project plan data for $stuff{'course'}</h1>\n";
# 
# $directory = $stuff{'data_file_path'} . "unsafe";
# 
# chdir $directory ||
#   print "Unable to cd to $directory!\n";
# 
# opendir (DIR, $directory) || print "Unable to open dir $directory!";
# @filenames = grep {/\.defect$/} readdir(DIR);
# closedir DIR;
# 
# print "</BODY>", "\n";
# print "</HTML>", "\n";
 






# here the real program starts

#  Mike Ward  mward@cs.utah.edu
#  CGI Statistics Script for Project Plan entries for entire class
# ---------------------------------------------------------------------

&readStuff;

$data_file_path = $stuff{'data_file_path'};

print "Content-type: text/html\n\n";

print "<HTML>\n";

print "<HEAD><TITLE>Project plan data for $stuff{'course'}\n";
print "</TITLE></HEAD>\n";
print "<BODY BGCOLOR=\"white\">\n";
print "<h1 align=center>Project plan data for $stuff{'course'}</h1>\n";

# Note: data[0]=prog_num, data[1]= est_loc, data[2]=est_hours, data[3]=est_minutes, data[4]=est_defects

$directory = $stuff{'data_file_path'} . "unsafe";

chdir $directory ||
  print "Unable to cd to $directory!\n";


# print "Changed directories to $directory.<br>\n";

# Find all the plan files in the directory
opendir (DIR, $directory) || print "Unable to open dir $directory!";
@filenames = grep {/\.estimate$/} readdir(DIR);
closedir DIR;

if ($#filenames < 0) {
   print "No project plan files found.</body></html>\n";
   exit;
   }


$numFiles = 0;

# print "About to initialize hashes.<br>\n";

# The following hashes are indexed by program number.  Since program number
# can now be any string, e.g. "4a", they've become hashes rather than
# arrays.  And instead of the 0 entry indicating the total-of-totals,
# each hash will have a "total" entry.
%total_plans = ( total => 0 );
%total_est_loc = ( total => 0 );
%total_est_time = ( total => 0 );
%total_est_locPerHour = ( total => 0 );
%total_est_defects = ( total => 0 );
%total_est_defectsPerKLOC = ( total => 0 );

# print "Initialized hashes.<br>\n";
# 
# print "Examining files: @filenames \n";

# print "Tracing...\n";
# print "<table border=1>\n";
# print "<tr><th>filename</th><th>prog_num</th><th>est_loc</th><th>est_hours</th><th>est_minutes</th><th>est_time</th><th>est_locPerHour</th><th>est_defects</th><th>est_defectsPerKLOC</th></tr>\n";

foreach $name (@filenames) {
  ($dev,$ino,$mode,$nlink,$uid,$gid,$rdev,$size,$atime,$mtime,$ctime,$blksize,$blocks) = lstat($name);
  if ($mode & 020000) {
    next; # it's a symlink
    }

#  print "<h2>$name</h2>\n";
#  print "Opening file $name ...<br>\n";
  open(THISFILE, "$name") || next;
#  print "Opened file $name!<br>\n";

  $numFiles++;
       
  while (<THISFILE>)  {

     @data = split(' ', $_);
     # print "Got a line of data: @data <br>\n";
   
     $prog_num = uc($data[0]);
     # print "prog_num = $prog_num.<br>";
     $est_loc = $data[1];
     # print "est_loc = $est_loc.<br>";
     $est_hours = $data[2];
     # print "est_hours = $est_hours.<br>";
     $est_minutes = $data[3];
     # print "est_minutes = $est_minutes.<br>";
     $est_time = $est_hours + $est_minutes/60;
     # print "est_time = $est_time.<br>";

# skip entries that would cause division by zero
     if ($est_loc <= 0 || $est_time <= 0) {
	next;
	}

     $est_locPerHour = $est_loc / $est_time;
     # print "est_locPerHour = $est_locPerHour.<br>";
     $est_defects = $data[4];
     # print "est_defects = $est_defects.<br>";
     $est_defectsPerKLOC = $est_defects * 1000 / $est_loc;
     # print "est_defectsPerKLOC = $est_defectsPerKLOC.<br>";
# print "<tr><td>$name</td><td>$prog_num</td><td>$est_loc</td><td>$est_hours</td><td>$est_minutes</td><td>$est_time</td><td>$est_locPerHour</td><td>$est_defects</td><td>$est_defectsPerKLOC</td>\n";

     unless (defined $total_plans{$prog_num}) { $total_plans{$prog_num} = 0; }
     $total_plans{$prog_num}++;
#      print "Incremented total_plans{",$prog_num,"} to ",$total_plans{$prog_num},"<br>\n";
     $total_plans{"total"}++;
     unless (defined $total_est_loc{$prog_num}) { $total_est_loc{$prog_num} = 0; }
     $total_est_loc{$prog_num} += $est_loc;
     $total_est_loc{"total"} += $est_loc;
     unless (defined $total_est_time{$prog_num}) { $total_est_time{$prog_num} = 0; }
     $total_est_time{$prog_num} += $est_time;
     $total_est_time{"total"} += $est_time;
     unless (defined $total_est_locPerHour{$prog_num}) { $total_est_locPerHour{$prog_num} = 0; }
     $total_est_locPerHour{$prog_num} += $est_locPerHour;
     $total_est_locPerHour{"total"} += $est_locPerHour;
     unless (defined $total_est_defects{$prog_num}) { $total_est_defects{$prog_num} = 0; }
     $total_est_defects{$prog_num} += $est_defects;
     $total_est_defects{"total"} += $est_defects;
     unless (defined $total_est_defectsPerKLOC{$prog_num}) { $total_est_defectsPerKLOC{$prog_num} = 0; }
     $total_est_defectsPerKLOC{$prog_num} += $est_defectsPerKLOC;
     $total_est_defectsPerKLOC{"total"} += $est_defectsPerKLOC;
     
     # print "</tr>\n";
     } 
# end while (<THISFILE>)
     close(THISFILE);
     # print "Closed file $name. <br>\n";
  }
# end foreach $name (@filenames)

# print "Got through first loop; about to print table.<br>\n";


# print "</table>\n";

if ($numFiles == 0) {
   print "Didn't find any project plans.</body></html>\n";
   exit;
   }

print "<h2>Average estimates:</h2>\n";
print "<p><table border=1>\n";
print "<tr><th>Program<br>number</th><th>Number of plans<br>submitted</th><th>Average<br>est. LOC</th><th>Average<br>est. time</th><th>Average<br>est. LOC/hr</th><th>Average<br>est. defects</th><th>Average<br>est. defects/KLOC</th></tr>\n";

@ukeys = keys %total_plans;
# print "Keys: ",@ukeys, "<br>\n";

@keys = sort {uc($a) cmp uc($b)} @ukeys;
# print "Sorted keys: ",@keys, "<br>\n";

# @keys = sort keys %total_plans;
# @keys = sort precedes_ci keys %total_plans;
# print "Keys in sorted order:<br>\n";
# foreach $i (@keys) {
#   my $n;
#   $n = $total_plans{$i};
#   print "total_plans{",$i,"} = ",$n,"<br>\n";
#   }
# print "OK, now let's print some information.<br>\n";
foreach $i (@keys) {
# for ($i = 1; $i <= $#total_plans; $i++) {
  if ($i eq "total") { next; }
  my $n;
  $n = $total_plans{$i};
#   print "total_plans{",$i,"} = ",$n,"<br>\n";
  unless ($n == 0) {
     $avg_est_loc = $total_est_loc{$i}/$n;
     $avg_est_time = $total_est_time{$i}/$n;
     $avgHours = int $avg_est_time;
     $avgMinutes = int (($avg_est_time-$avgHours)*60);
     $avg_est_locPerHour = $total_est_locPerHour{$i}/$n;
     $avg_est_defects = $total_est_defects{$i}/$n;
     $avg_est_defectsPerKLOC = $total_est_defectsPerKLOC{$i}/$n;
     print "<tr><td align=right>$i</td>";
     print "<td align=right>$n</td>";
     printf "<td align=right>%9.1f</td>",$avg_est_loc;
     printf "<td align=right>%u:%02u</td>",$avgHours,$avgMinutes;
     printf "<td align=right>%8.1f</td>",$avg_est_locPerHour;
     printf "<td align=right>%8.1f</td>",$avg_est_defects;
     printf "<td align=right>%8.3f</td>",$avg_est_defectsPerKLOC;
     print "</tr>\n";
     }
  }

$n = $total_plans{"total"};
unless ($n == 0) {
  $avg_est_loc = $total_est_loc{"total"}/$n;
  $avg_est_time = $total_est_time{"total"}/$n;
  $avgHours = int $avg_est_time;
  $avgMinutes = int (($avg_est_time-$avgHours)*60);
  $avg_est_locPerHour = $total_est_locPerHour{"total"}/$n;
  $avg_est_defects = $total_est_defects{"total"}/$n;
  $avg_est_defectsPerKLOC = $total_est_defectsPerKLOC{"total"}/$n;
  print "<tr><td align=right>Total</td>";
  print "<td align=right>$n</td>";
  printf "<td align=right>%9.1f</td>",$avg_est_loc;
  printf "<td align=right>%u:%02u</td>",$avgHours,$avgMinutes;
  printf "<td align=right>%8.1f</td>",$avg_est_locPerHour;
  printf "<td align=right>%8.1f</td>",$avg_est_defects;
  printf "<td align=right>%8.3f</td>",$avg_est_defectsPerKLOC;
  print "</tr>\n";
  }
print "</table>\n";

print "</BODY>", "\n";
print "</HTML>", "\n";
 




#!/usr/bin/perl
#
#&readStuff;
#
#while (($key,$value) = each %stuff) {
#    print "$key=$value\n";
#    }


sub readStuff {
  my @cookie_pairs = split (/;\s/, $ENV{'HTTP_COOKIE'});
  parse_pairs(@cookie_pairs);

  my $buffer;
  # read cookies first, so GET, POST, etc. can override cookies

  if ( $ENV{'REQUEST_METHOD'} eq "GET" ) {
    $buffer = $ENV{'QUERY_STRING'};
  } elsif ($ENV{'REQUEST_METHOD'} eq "POST") {
    read(STDIN,$buffer,$ENV{'CONTENT_LENGTH'});
  } else {
        # Added for command line debugging
        # Supply name/value form data as a command line argument
        # Format: name1=value1\&name2=value2\&...
        # (need to escape & for shell)
        # Find the first argument that's not a switch (-)
        $buffer = ( grep( !/^-/, @ARGV )) [0];
        $buffer =~ s/\\&/&/g;
  }

  my @pairs = split(/&/,$buffer);
  parse_pairs(@pairs);
  }

sub parse_pairs {
  my $pair;
  foreach $pair (@_) {
     my ($name, $value) = split(/=/, $pair);
	 # replace plus signs with spaces
         $value =~ tr/+/ /;
	 # convert escape characters to ASCII form 
	 $value =~ s/%([a-fA-F0-9][a-fA-F0-9])/pack("C", hex($1))/eg;

	 # Stop people from using subshells to execute commands
	 $value =~ s/~!/ ~!/g;

	 # Uncomment for debugging purposes
         # print "Setting $name to $value<P>";
 
         # place name/value pair into array $stuff 
         $stuff{$name} = $value;
  }
}

sub precedes_ci {
  return uc $_[0] cmp uc $_[1];
#   if (uc $_[0] lt uc $_[1]) {
#     return -1;
#     }
#   elsif (uc $_[0] eq uc $_[1]) {
#     return 0;
#     }
#   else {
#     return 1;
#     }
   }
