#!/perl -w
# NAME: cmpdefines.pl
# AIM: Compare TWO header files, and list and compare the #defines in each ..
# 2010/01/01 - Revisited, and updated...
# 01/06/2008 - Initial try - geoff mclane - http"//geoffair.net/mprerl ...
use strict;
use warnings;
unshift(@INC, 'C:/GTools/perl');
require 'logfile.pl' or die "Unable to load logfile.pl ...\n";
# log file stuff
my ($LF);
my $pgmname = $0;
if ($pgmname =~ /(\\|\/)/) {
	my @tmpsp = split(/(\\|\/)/,$pgmname);
	$pgmname = $tmpsp[-1];
}
my $perl_root = 'C:\GTools\perl';
my $outfile = $perl_root."\\temp.$pgmname.txt";
open_log($outfile);

my $inp_file1 = 'C:\Projects\grep\build\config.h';
my $inp_file2 = 'C:\Projects\grep\build\config2.h';

# features
my $load_log = 0;
my $verbosity = 0;

# debug
my $dbg1 = 0;
my $dbg2 = 0;

sub pgm_exit($$) {
   my ($val,$msg) = @_;
   if (length($msg)) {
      $msg .= "\n" if (!($msg =~ /\n$/));
      prt($msg);
   }
   close_log($outfile,$load_log);
   exit($val);
}

sub give_help($) {
   my ($arg) = @_;
   prt("Got argument [$arg]\n");
   prt("$pgmname: Version 0.0.1 2010-01-01\n");
   prt("Usage: [Options] in_file_1 in_file_2\n");
   prt("where the input files are headers with #define instructions...\n");
   prt("Options:\n");
   prt(" -h -?       = This help.\n");
   prt(" -v[v|<num>] = Set verbosity. Current=$verbosity\n");
   pgm_exit(0,'Help exit');
}

sub VERB1() { return ($verbosity >= 1); }
sub VERB2() { return ($verbosity >= 2); }
sub VERB3() { return ($verbosity >= 3); }
sub VERB4() { return ($verbosity >= 4); }
sub VERB5() { return ($verbosity >= 5); }
sub VERB9() { return ($verbosity >= 9); }

sub process_files($$) {
   my ($in_file1,$in_file2) = @_;
   my ($FH1, $FH2);
   my (@lines1, @lines2);
   my $lncnt1 = 0;
   my $lncnt2 = 0;
   my %defs1 = ();
   my %defs2 = ();
   my $line = '';
   my $def = '';
   my @arr = ();
   my $acnt = 0;
   my $key = '';
   my $val = '';
   my $i = 0;
   my $part = '';
   my ($cnt1, $cnt2, $cnt3);
   my $fnd = 0;
   my ($key1, $val1, $key2, $val2);
   my %done1 = ();
   my %same = ();
   my ($msg,$difv);
   my @notfound1 = ();
   my @diff1 = ();
   my @notfound2 = ();
   my @diff2 = ();
   if ( open $FH1, "<$in_file1" ) {
      if ( open $FH2, "<$in_file2" ) {
         @lines1 = <$FH1>;
         @lines2 = <$FH2>;
         close $FH1;
         close $FH2;
         $lncnt1 = scalar @lines1;
         $lncnt2 = scalar @lines2;
      } else {
         close $FH1;
         prt( "ERROR: Failed to open $in_file2 ...\n" );
         return;
      }
   } else {
      prt( "ERROR: Failed to open $in_file1 ...\n" );
      return;
   }
   if ($lncnt1 && $lncnt2) {
      prt( "Processing $lncnt1 from $in_file1, and ");
      prt( "$lncnt2 from $in_file2 ...\n");
      prt( "Doing 1 $in_file1 ... $lncnt1 ...\n" );
      foreach $line (@lines1) {
         chomp $line;
         if ($line =~ /^\s*#\s*define\s+(.*)/) {
            $def = $1;
            @arr = split(/\s/, $def);
            $acnt = scalar @arr;
            $key = $arr[0];
            if ($acnt > 1) {
               $val = '';
               for ($i = 1; $i < $acnt; $i++) {
                  $part = trim_all($arr[$i]);
                  if ($part =~ /^\//) {
                     if ((substr($part,1,1) eq '/')||(substr($part,1,1) eq '*')) {
                        last;
                     }
                  }
                  $val .= " " if length($val);
                  $val .= $part;
               }
            } else {
               $val = '<defined>';
            }
            prt( "$line ($def)\n" ) if ($dbg1);
            prt( "$key = $val\n" ) if ($dbg2);
            if (defined $defs1{$key}) {
               $defs1{$key} .= " && ". $val;
            } else {
               $defs1{$key} = $val;
            }
         }
      }

      prt( "Doing 2 $in_file2 ... $lncnt2 ...\n" );
      foreach $line (@lines2) {
         chomp $line;
         if ($line =~ /^\s*#\s*define\s+(.*)/) {
            $def = $1;
            @arr = split(/\s/, $def);
            $acnt = scalar @arr;
            $key = $arr[0];   # item being DEFINED
            if ($acnt > 1) {
               $val = '';
               for ($i = 1; $i < $acnt; $i++) {
                  $part = trim_all($arr[$i]);
                  if ($part =~ /^\//) {
                     if ((substr($part,1,1) eq '/')||(substr($part,1,1) eq '*')) {
                        last;
                     }
                  }
                  $val .= " " if length($val);
                  $val .= $part;
               }
            } else {
               $val = '<defined>';  # just DEFINED - no value given
            }
            prt( "$line ($def)\n" ) if ($dbg1);
            prt( "$key = $val\n" ) if ($dbg2);
            if (defined $defs2{$key}) {
               $defs2{$key} .= " && ". $val;
            } else {
               $defs2{$key} = $val;
            }
         }
      }
   }
   # done file scans
   # ===============

   $cnt1 = scalar keys(%defs1);
   $cnt2 = scalar keys(%defs2);
   if ($cnt1 && $cnt2) {
      prt( "Comparing $cnt1 from 1 [$in_file1],\n with $cnt2 from 2 [$in_file2]...\n" );

      ### SHOW RESULTS = COMPARE 1 WITH THOSE IN 2
      ####################################################################
      prt("\n") if (VERB2());
      prt( "Found in 1 ($cnt1), not in 2 ($cnt2) ...\n" ) if (VERB2());
      $cnt3 = 0;
      $difv = 0;
      foreach $key1 (keys %defs1) {
         $done1{$key1} = 1;   # set it as DONE this key
         $val1 = $defs1{$key1};
         $fnd = 0;
         $msg = '';
         foreach $key2 (keys %defs2) {
            if ($key1 eq $key2) {
               $fnd |= 1;
               $val2 = $defs2{$key2};
               if ($val1 eq $val2) {
                  $fnd |= 2;
                  $same{$key1} = $val1;
                  last;
               }
            }
         }
         if (!$fnd) {
            $msg = "$key1 = $val1\n";
            $cnt3++;
            push(@notfound1,$msg);
         } elsif ($fnd == 1) {
            $msg = "Found $key1, but different values\n 1=[$defs1{$key1}] vs 2=[$defs2{$key1}]\n";
            $difv++;
            push(@diff1,$msg);
         }
         prt($msg) if (VERB2() && length($msg));
      }
      prt( "End list of $cnt3, in 1, NOT found in 2\n");
      foreach $msg (@notfound1) {
         prt(" $msg");
      }
      if ($difv) {
         prt("And $difv with different value...");
         foreach $msg (@diff1) {
            prt(" $msg");
         }
      }

      ### COMPARE LIST IN 2, WITH 1
      prt("\n") if (VERB2());
      prt( "Found in 2 ($cnt2), not in 1 ($cnt1) ...\n" ) if (VERB2());
      $cnt3 = 0;
      $difv = 0;
      foreach $key2 (keys %defs2) {
         $val2 = $defs2{$key2};
         $fnd = 0;
         $msg = '';
         foreach $key1 (keys %defs1) {
            $val1 = $defs1{$key1};
            if ($key1 eq $key2) {
               $fnd |= 1;
               if ($val1 eq $val2) {
                  $fnd |= 2;
                  $same{$key1} = $val1;
                  last;
               }
            }
         }
         if (!$fnd) {
            $msg = "$key2 = $val2\n";
            $cnt3++;
            push(@notfound2,$msg);
         } elsif ($fnd == 1) {
            if ( ! defined $done1{$key2} ) {
               $msg = "Found $key2, but different values\n 1=[$defs1{$key2}] vs 2=[$defs2{$key2}]\n";
               $difv++;
               push(@diff2,$msg);
            }
         }
         prt($msg) if (VERB2() && length($msg));
      }
      prt( "End list of $cnt3 in 2, NOT found in 1\n");
      foreach $msg (@notfound2) {
         prt(" $msg");
      }

      if ($difv) {
         prt("And $difv with different value...\n");
         foreach $msg (@diff2) {
            prt(" $msg");
         }
      }


      $fnd = scalar keys(%same);
      if (VERB9()) {
         prt( "\nList of $fnd SAME key value defined...\n" );
         foreach $key1 (keys %same) {
            $val1 = $same{$key1};
            prt( "$key1 = $val1\n" );
         }
         prt( "End list of $fnd found to be the SAME...\n");
      } else {
         prt( "There are $fnd of SAME key value defined...\n" );
      }
   } else {
      # NOT got a count 1 or a count 2
      if ($cnt1) {
         prt("Got $cnt1 defines in 1, but NONE in 2\n");
      } elsif ($cnt2) {
         prt("Got $cnt2 defines in 2, but NONE in 1\n");
      } else {
         prt("Got NO #defines in either file!\n");
      }
   }
}

# #########################################
# MAIN

parse_args(@ARGV);

process_files($inp_file1,$inp_file2);

pgm_exit(0,"Normal exit.");

# #########################################

sub parse_args {
   my (@av) = @_;
   my ($arg,$cnt,$sarg);
   $cnt = 0;
   while (@av) {
      $arg = $av[0];
      if ($arg =~ /^-/) {
         if (($arg =~ /^-h/)||($arg =~ /^-\?/)) {
            # got request for HELP
            give_help($arg);
         } elsif ($arg =~ /^-v/) {
            $sarg = substr($arg,2);
            if (length($sarg)) {
               if ($sarg =~ /^v/) {
                  while ($sarg =~ /^v/) {
                     $verbosity++;
                     $sarg = substr($sarg,1);
                  }
                  if (length($sarg)) {
                     prt("ERROR: Unknown argument [$arg]... aborting...\n");
                     pgm_exit(1,"Error exit");
                  }
               } elsif ($sarg =~ /^\d+$/) {
                  $verbosity = $sarg;
               } else {
                  prt("ERROR: Unknown argument [$arg]... aborting...\n");
                  pgm_exit(1,"Error exit");
               }
            } else {
               $verbosity++;
            }
            prt("Set verbosity to $verbosity\n");
         } else {
            prt("ERROR: Unknown argument [$arg]... aborting...\n");
            pgm_exit(1,"Error exit");
         }
      } else {
         # plain item - assume file name
         if ($cnt == 0) {
            $inp_file1 = $arg;
            prt("Set input file 1 to [$inp_file1]\n");
         } elsif ($cnt == 1) {
            $inp_file2 = $arg;
            prt("Set input file 2 to [$inp_file2]\n");
         } else {
            prt("ERROR: Already have file 1=$inp_file1, and 2=$inp_file2\n");
            pgm_exit(1,"What is this? [$arg]! Aborting...\n");
         }
      }
      shift @av;
      $cnt++;
   }
   if (VERB2()) {
      $load_log = 1;
   }
}

# eof - cmpdefines.pl
