#!/Perl

# test file for doing a am2dsp4.cfg read, and check - geoff 11 April, 2006

my $IF_PATTERN = "^if[ \t]+\([A-Za-z][A-Za-z0-9_]*\)[ \t]*\(#.*\)?\$";
my $ELSE_PATTERN = "^else[ \t]*\(#.*\)?\$";
my $ENDIF_PATTERN = "^endif[ \t]*\(#.*\)?\$";

my $verbose = 0;
my $verbose2 = 0;
my @excluded_dirs = ();
my @excluded_files = ();
my $msvc_cflags = "";
my $msvc_threads = "";
my $msvc_libs = "";
my @extra_sources = ();
my @extra_projects = ();

# new variables
my $msvc_dlibs = "";
my $msvc_rlibs = "";
my $in_debug = 0;
my $in_release = 0;
my $do_check = 0;
my $def_cfg = "am2dsp4.cfg";
my $root_dir = '';
my $src_cfg = $def_cfg;
my @msvc_dlibs_list = ();
my @msvc_rlibs_list = ();
my @msvc_libs_list = ();
my @msvc_dlibs_paths = ();
my @msvc_rlibs_paths = ();
my @msvc_libs_paths = ();
my @msvc_inc_paths = ();
my @test_headers = ( 'zlib.h', 'AL/al.h', 'AL/alut.h',
  'simgear/compiler.h', 'simgear/debug/logstream.hxx', 'plib/pu.h' );

# Extracted from AM_INIT_AUTOMAKE(package,version)
my $dsp_package = 'FGFS';
my $dsp_version = '0.2';

my $static_lib = 0;

parse_arguments(@ARGV);

read_am2dsprc($src_cfg);
if ($do_check) {
	check_includes();
}

# debug stuff only
if ($verbose) {
	print "msvc_libs = [$msvc_libs] ...\n";
	print "msvc_dlibs = [$msvc_dlibs] ...\n";
	print "msvc_rlibs = [$msvc_rlibs] ...\n";
}
if ($verbose == 2) {
	my $item = '';
	my $cnt = 0;
	print "msvc_cflags = [$msvc_cflags] ...\n";
	print "excluded_dirs ...\n";
	$cnt = 0;
	foreach $item (@excluded_dirs) {
		$cnt++;
		print "$cnt [$item] ...\n";
	}
	print "Done $cnt excluded_dirs ...\n";
	print "excluded_files ...\n";
	$cnt = 0;
	foreach $item (@excluded_files) {
		$cnt++;
		print "$cnt [$item] ...\n";
	}
	print "Done $cnt excluded_files ...\n";
	print "extra_sources ...\n";
	$cnt = 0;
	foreach $item (@extra_sources) {
		$cnt++;
		print "$cnt [$item] ...\n";
	}
	print "Done $cnt extra_sources ...\n";
	print "extra_projects ...\n";
	$cnt = 0;
	foreach $item (@extra_projects) {
		$cnt++;
		print "$cnt [$item] ...\n";
	}
	print "Done $cnt extra_projects ...\n";
}

exit 0;

sub add_2_msvc {
	my $flg = shift;
	if ($in_debug) {
		$msvc_dlibs .= $flg;
	} elsif ($in_release) {
		$msvc_rlibs .= $flg;
	} else {
		$msvc_libs .= $flg;
	}
}

sub add_2_libs {
	my $flg = shift;
	if ($in_debug) {
		push(@msvc_dlibs_list, $flg);
	} elsif ($in_release) {
		push(@msvc_rlibs_list, $flg);
	} else {
		push(@msvc_libs_list, $flg);
	}
}

sub add_2_libpaths {
	my $flg = shift;
	if ($in_debug) {
		push(@msvc_dlibs_paths, $flg);
	} elsif ($in_release) {
		push(@msvc_rlibs_paths, $flg);
	} else {
		push(@msvc_libs_paths, $flg);
	}
}


sub read_am2dsprc {
    my $rc_file = shift;

    open( RC_FILE, $rc_file )
	or die "Can't open $rc_file: $!\n";
    my $line;
	my @cond_stack = ();
    while (defined($line = <RC_FILE>)) {
	chomp $line;
	if ($line =~ s/\\$//) {
	    # continuation line
	    $line .= "%";
	    $line .= <RC_FILE>;
	    redo unless eof(RC_FILE);
	}

	next if $line =~ /^$/; # ignore blank lines
	next if $line =~ /^#/; # ignore comments

	if ($line =~ /exclude_dir\s*=\s*(\S+)/) {
	    push( @excluded_dirs, $1 );
	}
	elsif ($line =~ /exclude_file\s*=\s*(\S+)/) {
	    my $f;
	    ($f = $1) =~ s/\\/\\\\/g; # escape path separators, "\" -> "\\"
	    push( @excluded_files, $f );
	    print "Excluding file: $f\n" if $verbose;
	}
	elsif ($line =~ /include_path\s*=\s*(\S+)/) {
	    $msvc_cflags .= " /I \"$1\"";
		push(@msvc_inc_paths, $1);
	}
	elsif ($line =~ /define\s*=\s*(\S+)/) {
	    $msvc_cflags .= " /D \"$1\"";
	}
	elsif ($line =~ /lib_path\s*=\s*(\S+)/) {
	    add_2_msvc( " /libpath:\"$1\"" );
		add_2_libpaths( "$1" );
	}
	elsif ($line =~ /add_lib\s*=\s*(\S+)/) {
	    add_2_msvc( " $1.lib" );
		add_2_libs( "$1.lib" );
	}
	elsif ($line =~ /type\s*=\s*(\S+)/) {
	    my ($type,$threads,$debug) = split /,/, $1;
	    print "type=$type, threading=$threads, debug=$debug\n" if $verbose;
	    if ($type =~ "ConsoleApplication") {
		$static_lib = 0
	    }
	    elsif ($type =~ "StaticLibrary") {
		$static_lib = 1
	    }
	    else {
		# Invalid type
	    }

	    my $flags = " /ML"; # single threaded.
	    if ($threads =~ /Multithreaded/) {
		$flags = " /MT";
	    }
	    elsif ($threads =~ /Singlethreaded/) {
		$flags = " /ML";
	    }
	    else {
		# Invalid threading option.
	    }

	    if ($debug =~ /Debug/) {
		$flags .= "d";
	    }

	    $msvc_cflags .= $flags;
	}
	elsif ($line =~ /add_source_file\s*=\s*(.*)/) {
	    my $rule;
	    ($rule = $1) =~ s/%/\r\n/g;
	    push( @extra_sources, $rule );
	}
	elsif ($line =~ /add_project\s*=\s*(.*)/) {
	    push( @extra_projects, $1 );
	}
	elsif ($line =~ /$IF_PATTERN/o) {
		if ($1 =~ /Debug/io) {
			print "Entering DEBUG ...\n" if $verbose2;
			$in_debug = 1;
			$in_release = 0;
		} elsif ($1 =~ /Release/io) {
			print "Entering RELEASE ...\n" if $verbose2;
			$in_release = 1;
			$in_debug = 0;
		} else {
			print "EEK! Got $1 ...\n";
			die "Presently ONLY if switch is 'Debug' or 'Release'!\n";
		}
	    push (@cond_stack, "\@" . $1 . "_TRUE\@");
	}
	elsif ($line =~ /$ELSE_PATTERN/o) {
		if (! @cond_stack) {
		    die "else without if!\n";
		}
	    elsif ($cond_stack[$#cond_stack] =~ /_FALSE\@$/) {
			die "else after an else!\n";
		} else {
			if ($in_debug) {
				print "Switch to RELEASE ...\n" if $verbose2;
				$in_debug = 0;
				$in_release = 1;
			} else {
				print "Switch to DEBUG ...\n" if $verbose2;
				$in_debug = 1;
				$in_release = 0;
			}
			$cond_stack[$#cond_stack] =~ s/_TRUE\@$/_FALSE\@/;
		}
	}
	elsif ($line =~ /$ENDIF_PATTERN/o) {
	    if (! @cond_stack) {
			die "endif without if!\n";
		}
		print "Exit $cond_stack[$#cond_stack] ...\n" if $verbose2;
		pop (@cond_stack);
		$in_debug = 0;
		$in_release = 0;
	}

    } # end while


    close(RC_FILE);
}


sub give_little_help {
	print "am2dsp4: Just a little help ...\n";
	print "--help (or -h, -?) - This brief help!\n";
	print "--version          - Does nothing?\n";
	print "--verbose (or -v)  - Sets verbose mode. (-v2 for MORE)\n";
	print "--package name     - Set the DSP package name (default = $dsp_package)\n";
	print "--lib (or -l)      - To create static library (Default is console app.)\n";
	print "--dir path         - Establish input path for $def_cfg.\n";
	print "--check (or -c)    - Check libraries, and some known include files, and exit.\n";
	print "Any other option with '-' will abort, with a complaint ...\n";
	die   "Any other input    - is ignored ...\n";
}

sub set_config {
	my $cfg = shift;
	if ( !(($cfg =~ /\/$/) || ($cfg =~ /\\$/)) ) {
		$cfg .= '\\';
	}
	my $fil = $cfg . $def_cfg;
	if( -r $fil ) {
		$src_cfg = $fil;
		$root_dir = $cfg;
	} else {
		# a thought to use 'source' folder, but later abandoned!
		#$fil = $cfg . 'source\\' . $def_cfg;
		#if( -r $fil ) {
		#	$src_cfg = $fil;
		#	$root_dir = $cfg . 'source\\';
		#} else {
			die "ERROR: Can NOT locate $def_cfg on the path $cfg, nor $cfg\\source! ... aborting!\n";
		#}
	}
	print "Using root path [$root_dir] to find file $src_cfg ...\n";
}

sub parse_arguments {
    my @av = @_;

    while (@av) {
	if ($av[0] eq '--version') {
		# does nothing
	} elsif ($av[0] eq '--help' || $av[0] eq '-h' || $av[0] eq '-?') {
		give_little_help();
	} elsif ($av[0] eq '--verbose' || $av[0] eq '-v') {
	    $verbose = 1;
	} elsif ($av[0] eq '--package' || $av[0] eq '-p') {
	    require_argument(@av);
	    shift @av;
	    $dsp_package = $av[0];
	} elsif ($av[0] eq '--lib' || $av[0] eq '-l') {
	    # Create a static library
	    $static_lib = 1;
	} elsif ($av[0] eq '--dir') {
	    require_argument(@av);
	    shift @av;
		set_config($av[0]);
	} elsif ($av[0] eq '--check' || $av[0] eq '-c') {
		$do_check = 1;
	} elsif ($av[0] eq '-v2' ) {
		$verbose2 = 1;
	} elsif ($av[0] =~ /^-/) {
	    die "am2dsp4: unrecognised option -- `$av[0]'\nTry am2dsp --help for more information.\n";
	} else {
	}
	shift @av;
    }
}

# Ensure argument exists, or die.
sub require_argument
{
    my ($arg, @arglist) = @_;
    die "am2dsp4: no argument given for option '$arg'\n"
        if ! @arglist;
}

sub subroot {
	my ($rt, $fi) = @_;
	my $l1 = length($rt);
	my $l2 = length($fi);
	if ($l1 <= $l2) {
		$rt = substr($fi, $l1);
	} else {
		$rt = $fi;
	}
	return $rt;
}

sub check_lib_paths {
	my $fil = shift;
	my $inc = '';
	my $ff = '';
	my $found = 0;
	if( ! $found ) {
		foreach $inc (@msvc_libs_paths) {
			$ff = $root_dir . $inc;
			if ( !(($ff =~ /\/$/) || ($ff =~ /\\$/)) ) {
				$ff .= '\\';
			}
			$ff .= $fil;
			if( -f $ff ) {
				$found = 1;
				last;
			}
		}
	}
	if( ! $found ) {
		foreach $inc (@msvc_rlibs_paths) {
			$ff = $root_dir . $inc;
			if ( !(($ff =~ /\/$/) || ($ff =~ /\\$/)) ) {
				$ff .= '\\';
			}
			$ff .= $fil;
			if( -f $ff ) {
				$found = 1;
				last;
			}
		}
	}
	if( ! $found ) {
		foreach $inc (@msvc_dlibs_paths) {
			$ff = $root_dir . $inc;
			if ( !(($ff =~ /\/$/) || ($ff =~ /\\$/)) ) {
				$ff .= '\\';
			}
			$ff .= $fil;
			if( -f $ff ) {
				$found = 1;
				last;
			}
		}
	}
	if( $found ) {
		print "Found $fil in $inc [$ff] ...\n" if $verbose2;
	} else {
		print "WARNING: Unable to locate $fil ...\n" if $verbose2;
	}
	return $found;
}

sub check_inc_paths {
	my $fil = shift;
	my $inc = '';
	my $ff = '';
	my $found = 0;
	if( ! $found ) {
		foreach $inc (@msvc_inc_paths) {
			$ff = $root_dir . $inc;
			if ( !(($ff =~ /\/$/) || ($ff =~ /\\$/)) ) {
				$ff .= '\\';
			}
			$ff .= $fil;
			### print "Checking for $fil in $ff ...\n" if $verbose9;
			if( -f $ff ) {
				$found = 1;
				last;
			}
		}
	}
	if( $found ) {
		print "Found $fil in $inc [$ff] ...\n" if $verbose2;
	} else {
		print "WARNING: Unable to locate $fil ...\n" if $verbose2;
	}
	return $found;
}

sub check_includes {
	# check for a known set of INCLUDE files
	my $fil = '';
	my $ff = '';
	my $cnt1 = 0;
	my $cnt2 = 0;
	my @missed = ();
	my @missed2 = ();
	$cnt1 = scalar @msvc_dlibs_list + scalar @msvc_rlibs_list + scalar @msvc_libs_list;
	print "Check each $cnt1 additional library, in each library include path ...\n" if $verbose;
	$cnt1 = 0;
	foreach $fil (@msvc_dlibs_list) {
		$cnt1++;
		if( check_lib_paths( $fil ) == 0 ) {
			push(@missed, $fil);
		}
	}
	foreach $fil (@msvc_rlibs_list) {
		$cnt1++;
		if( check_lib_paths( $fil ) == 0 ) {
			push(@missed, $fil);
		}
	}
	foreach $fil (@msvc_libs_list) {
		$cnt1++;
		if( check_lib_paths( $fil ) == 0 ) {
			push(@missed, $fil);
		}
	}
	$cnt2 = scalar @test_headers;
	print "Check each of $cnt2 test headers, in each include path ...\n" if $verbose;
	foreach $fil (@test_headers) {
		$cnt2++;
		if( check_inc_paths( $fil ) == 0 ) {
			push(@missed2, $fil);
		}
	}

	print "Done checking $cnt1 libraries, and $cnt2 test includes ...\n";
	if( @missed ) {
		print "WARNING: Missed ". join(' ',@missed) . ".\n";
		print "Check 'add_lib' and 'lib_path' in $src_cfg ...\n";
	}
	if( @missed2 ) {
		print "WARNING: Missed ". join(' ',@missed2) . ".\n";
		print "Check 'include_path' in $src_cfg ...\n";
	}

	die "End check of libraries and include files ... aborting ...\n";
}

# eof - readcfg.pl
