#!/bin/perl
#File: perlstat

#This program reads a file and counts all occurrances of "sub " at the beginning
#of lines.  Assuming these are subroutine (function) definitions with a body
#(ie. pair of matched "{}"), I increment a counter to count them, record the
#line number it starts on in a hash with the sub name as a index, and count the 
#number of lines until the next "sub " to give a rough estimate of lines in the 
#sub. And then print out the stats to stdout.  
#Usage  perlstat file [file...] [ | tee statfile]


if (! @ARGV)
 {
  print <<END;
   ERROR! Insufficient arguments. At least one perl source file name required.
   USAGE: $0 file [file ...] [ | tee statfile]

END
  exit 1;
 }
$total_executable_lines = 0; #executable lines excluding comments and lines with
			     #only braces and/or comments
$package_array{main}++;      #package names
%sub_array = {};             #sub names

foreach $file (@ARGV)
 {
  open (INFILE,$file) || warn "Can't open $file!";
  if (INFILE)
   {
    $brace_count = 0;
    while ( $inline = <INFILE>)
     {
      $open_brace = "";
      next if ( $inline =~ /^[\s]*#/ );#skip comment only lines
      #print $inline,"\n";
      if (($sub_name, $rest_of_line) = 
				    ($inline =~ /^[\s]*sub ([^\s{]*)([^#]*).*$/))
       {
	$sub_array{$sub_name} = $.; #keeps tracks of subs and where they begin
	$current_sub = $sub_name;
	&parse_and_total ($sub_name.$rest_of_line);
       }#if it's a subroutine
      else
       {
        $inline =~ s/(^[^#]*).*$/$1/;
	&parse_and_total ($inline);
       }#if it's not a subroutine
     }#while loop to read file
    &print_stats();
   }#if open of INFILE successful
 }#foreach $file (@ARGV)

sub parse_and_total
 {
  my ($inline) = @_;
  chomp $inline;
  if ($inline =~ /[^{}\s]+/)
   {
    ++$total_executable_lines ;
    $sub_linecount{$current_sub}++;
   }#if not just brace(s)
  $package_array{$1}+= $. 
   if (($inline =~ /^[^#]*package ([^\s{]*)([^#]*).*;$/) &&
       (! $package_array{$1}));#keep track of first reference to packages
  @inline = split ("",$inline);
  $brace_count += grep /[{]/,@inline;
  $brace_count -= grep /[}]/,@inline;
 }#parse_and_total

sub print_stats
 {
  my $number_of_subs = @sub_names = keys %sub_array;
  my $number_of_packages = @package_names = keys %package_array;
  my $total_sub_lines = 0;#number of lines in subroutines
  print "Statistics for $file:\n\n";
  printf ("     %-50s%10d\n",
   "Number of total executable lines:",$total_executable_lines);
  printf ("     %-50s%10d\n",
          "Number of subroutines referenced:",$number_of_subs);
  printf ("     %-50s%10d\n",
          "Number of packages (including main):",$number_of_packages);
  print "\n\n";
  print "Packages in sorted order: \n\n";
  foreach $key (sort (keys %package_array))
   {
    printf ("     Package \"%s\" first referenced at line %d\n",
     $key,$package_array{$key});
   }
  print "\n\n";
  print "Subroutines in sorted order: \n\n";
  foreach $key (sort (keys %sub_array))
   {
    printf ("  %-40s with %d lines, at line %d\n",
     $key,$sub_linecount{$key},$sub_array{$key});
    $total_sub_lines += $sub_linecount{$key};
   }
  printf ("  %-40s with %d lines\n",
   "main",$total_executable_lines - $total_sub_lines);
 }#print_stats
