#!/perl -w
# NAME: scanconfac.pl
# AIM: Scan a configure.ac file
use strict;
use warnings;
use File::Basename;	# to split path into ($name, $dir) = fileparse($ff); or ($nm,$dir,$ext) = fileparse( $fil, qr/\.[^.]*/ );
require 'logfile.pl' or die "Unable to load logfile.pl ...\n";
# log file stuff
my ($LF);
my $pgmname = $0;
if ($pgmname =~ /\w{1}:\\.*/) {
   my @tmpsp = split(/\\/,$pgmname);
   $pgmname = $tmpsp[-1];
}
my $outfile = "temp.$pgmname.txt";
open_log($outfile);
prt( "$0 ... Hello, World ...\n" );

my $inp_file = "C:\\FGCVS\\FlightGear\\source\\configure.ac";

my %configac_hash = ();
my %ac_scanned = ();
my $dsp_package = '';
my $dsp_version = '';

my $sconfig_ac_macros = 'config_ac_macros';
my $config_names = 'config_names';
my $config_headers = 'config_headers';
my $config_fullnames = 'config_fullnames';
my $make_input_list = 'make_input_list';
my $other_input_files = 'other_input_files';
my $make_list = 'make_list';
my $cfg_defines = 'cfg_defines';
my $sconfigure_cond = 'configure_cond';
my $svar_hash = 'var_hash';

my $AM_CONDITIONAL_PATTERN = "AM_CONDITIONAL\\((\\w+)";
my $AM_INIT_AUTOMAKE = "AM_INIT_AUTOMAKE\\(([^,]+),[ \t]*([^)]+)";

# debug
my $dbg_c01 = 0;  # prt( "[dbg_c01] [$cline]\n" ) if ($dbg_c01);
my $dbg_c02 = 0;  # prt( "[dbg_c02] Storing configure_cond key $1 ... value=2\n" ) if ($dbg_c02);
my $dbg_c02a = 0; # prt( "[dbg_c02a] $aclnum: [$acline]\n" ) if ($dbg_c02a);
my $dbg_c03 = 0;  # prt( "[dbg_c03] Num Variable $1=$2\n" ) if ($dbg_c03);
my $dbg_c03a = 0; # prt( "[dbg_c03a] MACRO [$key]=[$nval]\n" ) if ($dbg_c03a);
my $dbg_c04 = 0;  # prt( "[dbg_c04] Got ac_output_line = [$ac_output_line] ...\n" ) if ($dbg_c04);
my $dbg_c05 = 0;  # prt( "[dbg_c05] Adding $input [$ff] to make_input_list ...\n" ) if ($dbg_c05);
my $dbg_c27 = 0;  # prt( "[dbg_c27] Checking substitution for [$item] ...\n" ) if ($dbg_c27);

sub set_all_debug_on() {
   $dbg_c01 = 1;
   $dbg_c02 = 1;
   $dbg_c02a = 1;
   $dbg_c03 = 1;
   $dbg_c03a = 1;
   $dbg_c04 = 1;
   $dbg_c05 = 1;
   $dbg_c27 = 1;
}

sub scan_one_configure_file($$);


sub do_hash_setup($) {
   my ($hr) = @_;
   ${$hr}{$sconfig_ac_macros} = { };
   ${$hr}{$config_names} =[];
   ${$hr}{$config_headers} =[];
   ${$hr}{$config_fullnames} = [];
   ${$hr}{$make_input_list} = [];
   ${$hr}{$other_input_files} = [];
   ${$hr}{$make_list} = { };
   ${$hr}{$cfg_defines} = { };
   ${$hr}{$sconfigure_cond} = { };
   ${$hr}{$svar_hash} = { };
}

## my %config_ac_macros = ();
sub sac_do_macro_sub2($$) {
	my ($hr,$item) = @_;
   my $rconfig_ac_macros = ${$hr}{$sconfig_ac_macros};
	prt( "[dbg_c27] Checking substitution for [$item] ...\n" ) if ($dbg_c27);
	if (defined ${$rconfig_ac_macros}{$item}) {	# if it is IN the MACROS
		my $ritem = ${$rconfig_ac_macros}{$item};	# extract the substitute value
		prt( "[dbg_c27] Found: returning [$ritem] ...\n" ) if ($dbg_c27);
		return $ritem;
	}
	return $item;
}


sub sac_do_macro_sub($$) {
	my ($hr,$item) = @_;
	if ($item =~ /^\$/) {
		my $msub = substr($item,1);	# remove leading '$'
		my $ritem = do_macro_sub2($hr,$msub);
		if ($ritem ne $msub) {
			return $ritem;
		}
	}
	return $item;
}


sub scan_one_configure_file($$) {
   my ($filename,$hr) = @_;
	if( defined $ac_scanned{$filename}) {
		return;
	}
   if (! open(CONFIGURE, $filename) ) {
      prtw( "WARNING: can't open '$filename': $!\n" );
      return;
   }

	$ac_scanned{$filename} = 1;
   my $rconfig_ac_macros = ${$hr}{$sconfig_ac_macros};
   my $rconfig_names = ${$hr}{$config_names};
   my $rconfig_headers = ${$hr}{$config_headers};
   my $rconfig_fullnames = ${$hr}{$config_fullnames};
   my $rmake_input_list = ${$hr}{$make_input_list};
   my $rother_input_files = ${$hr}{$other_input_files};
   my $rmake_list = ${$hr}{$make_list};
   my $rcfg_defines = ${$hr}{$cfg_defines};
   my $rconfigure_cond = ${$hr}{$sconfigure_cond};
   my $rvar_hash = ${$hr}{$svar_hash};

   my ($fn,$rd) = fileparse($filename);
   prt( "Processing configure file - $filename ...\n" );
   my $in_ac_output = 0;
   my $ac_output_line = '';
   my $ff = '';
	my $fline = '';
	my $cline = '';
	my $acline = '';
	my $aclnum = 0;
	#my %var_hash = ();
	my $key  = '';
	my $nval = '';
   while (<CONFIGURE>) {
		$fline = $_;	# get current file line
		$cline = $fline;	# copy current file line
		chomp $cline;
		$acline = trim_all($cline);
		$aclnum++;
		###prt( "$cline\n" );
		# Remove comments from current line.
		s/\bdnl\b.*$//;
		s/\#.*$//;
		$cline =~ s/\bdnl\b.*$//;
		$cline =~ s/\#.*$//;
		next if (length($cline) == 0);
		prt( "[dbg_c01] [$cline]\n" ) if ($dbg_c01);
		if ($cline =~ /^(\w+)="(\d+)"$/) {
			prt( "[dbg_c03] Num Variable $1=$2\n" ) if ($dbg_c03);
			${$rvar_hash}{$1} = $2;
		##} elsif ($cline =~ /^(\w+)="(.+)"$/) {
		##} elsif ($cline =~ /^(\w+)="{0,1}(.+)"{0,1}$/) {
		##} elsif ($cline =~ /^(\w+)=(.+)$/) {
		} elsif ($cline =~ /^\s*(\w+)=(.+)$/) {
			$key  = $1;
			$nval = $2;
			if (substr($nval,0,1) eq '"') {
				$nval = substr($nval,1, length($nval)-2);
			}
			prt( "[dbg_c03a] MACRO [$key]=[$nval]\n" ) if ($dbg_c03a);
			if (index($nval,'.') != -1) {
				my @varr = split(/\./,$nval);
				$nval = '';
				my $vlen = scalar @varr;
				prt( "[dbg_c03] Split to $vlen components ...\n" ) if ($dbg_c03);
				for (my $i = 0; $i < $vlen; $i++) {
					my $ky = trim_all($varr[$i]);
					prt( "Conponent $ky\n" ) if ($dbg_c03);
					if (substr($ky,0,1) eq '$') {
						$ky = substr($ky,1);
						if (defined ${$rvar_hash}{$ky}) {
							$nval .= '.' if (length($nval));
							$nval .= ${$rvar_hash}{$ky};
						} else {
							$nval .= '.' if (length($nval));
							$nval .= $ky;
						}
					} else {
						$nval .= '.' if (length($nval));
						$nval .= $ky;
					}
				}
			}
			prt( "[dbg_c03] Available substitute [$key]=[$nval]\n" ) if ($dbg_c03);
			${$rvar_hash}{$key} = $nval;
			${$rconfig_ac_macros}{$key} = $nval;
		} elsif ($cline =~ /^(\w+)=(.+)$/) {
			$key  = $1;
			$nval = $2;
			prtw( "WARNING: This should have already been processed!\nWARNING: Variable [$key]=[$nval] no quotes\n\n" );
		}

		# Skip macro definitions.  Otherwise we might be confused into
		# thinking that a macro that was only defined was actually
		# used.
		next if /AC_DEFUN/;

		# Follow includes.  This is a weirdness commonly in use at
		# Cygnus and hopefully nowhere else.
		if (/sinclude\((.*)\)/ && -f ($rd . $1)) {
			$ff = $rd . $1;
			scan_one_configure_file ($ff, $hr);
		}

		if (! $in_ac_output && ( s/AC_OUTPUT\s*\(\[?// || s/AC_CONFIG_FILES\s*\(\[?// ) ) {
			$in_ac_output = 1;
			#$ac_output_line = $.;	# get LINE number
			prt( "[dbg_c04] Got ac_output_line = [$ac_output_line] ...\n" ) if ($dbg_c04);
		}

		if ($in_ac_output) {
			my $closing = 0;
			if (s/[\]\),].*$//) {
				$in_ac_output = 0;
				$closing = 1;
			}

			# Look at potential Makefile.am's
			foreach (split) {
				# Must skip empty string for Perl 4.
				next if $_ eq "\\" || $_ eq '';

				my ($local,$input,@rest) = split(/:/);
				if (! $input) {
					$input = $local;
				} else {
					$input =~ s/\.in$//;
				}
				$ff = $rd . $input . '.am';
				if (-f $ff) {
					prt( "[dbg_c05] Adding $input [$ff] to make_input_list ...\n" ) if ($dbg_c05);
					push(@{$rmake_input_list}, $input);
					${$rmake_list}{$input} = join(':', ($local,@rest));
				} else {
					prt( "[dbg_c05] Adding $input [$ff] to other_input_files ...\n" ) if ($dbg_c05);
					# We have a file that automake should cause to be
					# rebuilt, but shouldn't generate itself.
					push (@{$rother_input_files}, $_);
				}
			}
		}

		# Handle configuration headers.  A config header of `[$1]'
		# means we are actually scanning AM_CONFIG_HEADER from
		# aclocal.m4.
		if (/A([CM])_CONFIG_HEADER\s*\((.*)\)/ && $2 ne '[$1]') {
			am_conf_line_error($filename, $., "automake requires AM_CONFIG_HEADER, not AC_CONFIG_HEADER")
					if $1 eq 'C';
			#$config_header_line = $.;
			my ($one_hdr);
			foreach $one_hdr (split (' ', $2)) {
				push (@{$rconfig_fullnames}, $one_hdr);
				if ($one_hdr =~ /^([^:]+):(.+)$/) {
					push (@{$rconfig_names}, $1);
					push (@{$rconfig_headers}, $2);
				} else {
					push (@{$rconfig_names}, $one_hdr);
					push (@{$rconfig_headers}, $one_hdr . '.in');
				}
			}
		}

		if (/$AM_CONDITIONAL_PATTERN/o) {
			prt( "[dbg_c02a] $aclnum: [$acline]\n" ) if ($dbg_c02a);
			if ( defined ${$rcfg_defines}{$1} ) {
				# has been DEFINED in am2dsp?.cfg file, or previously defined
				prt( "[dbg_c02] Storing configure_cond key $1 ... value=2\n" ) if ($dbg_c02);
				${$rconfigure_cond}{$1} = 2;
			} else {
				prt( "[dbg_c02] Storing configure_cond key $1 ... value=1\n" ) if ($dbg_c02);
				${$rconfigure_cond}{$1} = 1;
			}
		}

		if (/$AM_INIT_AUTOMAKE/o) {
			$dsp_package = $1;
			$dsp_version = $2;
			prt( "Got AM_INIT_AUTOMAKE($dsp_package, $dsp_version) ...\n" );
         ${$hr}{$sconfig_ac_macros} = $rconfig_ac_macros;
			$dsp_package = sac_do_macro_sub($hr,$dsp_package);
			$dsp_version = sac_do_macro_sub($hr,$dsp_version);
			prt( "Set DSP package = $dsp_package, DSP version = $dsp_version ...\n" );
		}
    }

    close(CONFIGURE);
}

sub show_hash_ref($$);
sub show_array_ref($$);

sub show_array_ref($$) {
   my ($ar,$ind) = @_;
   my ($key,$ref,$cnt,$nind,$msg);
   $nind = "$ind ";
   $cnt = 0;
   foreach $key (@{$ar}) {
      $ref = ref($key);
      $cnt++;
      $msg = $ind.sprintf("%3d",$cnt);
      if ($ref eq 'HASH') {
         prt("$msg: key is $ref\n");
         show_hash_ref($key,$nind);
      } elsif ($ref eq 'ARRAY') {
         prt("$msg: key is $ref\n");
         show_array_ref($key,$nind);
      } else {
         prt("$msg: array value: $key\n");
      }
   }
}

sub show_hash_ref($$) {
   my ($hr,$ind) = @_;
   my ($key,$val,$ref,$cnt,$nind,$msg);
   $cnt = 0;
   $nind = "$ind ";
   foreach $key (keys %{$hr}) {
      $val = ${$hr}{$key};
      $ref = ref($val);
      $cnt++;
      $msg = $ind.sprintf("%3d",$cnt);
      if ($ref eq 'HASH') {
         prt("$msg: $key value $ref\n");
         show_hash_ref($val,$nind);
      } elsif ($ref eq 'ARRAY') {
         prt("$msg: $key value $ref\n");
         show_array_ref($val,$nind);
      } else {
         prt("$msg: hash $key = $val\n");
      }
   }
}

set_all_debug_on();
do_hash_setup(\%configac_hash);
scan_one_configure_file($inp_file, \%configac_hash);
prt("\nOutput of HASH collected...\n");
show_hash_ref(\%configac_hash,"");

close_log($outfile,1);
exit(0);

# eof
