#!/perl -w
# NAME: fgcmp2dsps.pl
# AIM: Comparison of TWO DSP files - show different SOURCE files only ...
# 26/10/2008 - added parse_args() for INPUT files
# 13/08/2008 geoff mclane http://geoffair.net/mperl
# Compares SOURCE lists, and compares the config parameters ...
use strict;
use warnings;
use File::Basename;
use File::stat;
use Cwd;
require 'fgutils.pl' or die "Unable to load fgutils.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);

# USER INPUT
my $in_file1 = 'C:\FG\20\temp...#FlightGear.FlightGear.dsp';
my $in_file2 = 'C:\FG\20\FlightGear\FlightGear.dsp';
##my $in_file1 = 'temp...#FlightGear.FlightGear.dsp';
##my $in_file2 = 'FlightGear\FlightGear.dsp';

# USER OPTIONS
my $also_show_matched = 0;  # also output MATCHED files
my $also_show_moved = 1;    # show any MOVED files
my $ignore_headers = 1;
my $minlen1 = 40;
my $minlen2 = 61;

# DEBUG STUFF
my $dbg_dsp = 0;
my $dbg_ds1 = 0;
my $dbg_ds2 = 0;
my $dbg_ds3 = 0;
my $dbg_ds4 = 0;	# show CPP and LINK config items - %v6_conf
my $dbg_ds5 = 0;	# show Defined items - %v6_defs
my $dbg_ds6 = 0;	# show !IF, !ELSEIF switching
my $dbg_ds7 = 0;	# show %v6_conf listing
my $big_dbg = 0;
my $dbg_ds8 = 0;	# show VC6 Filter and Group Name
my $dbg_ds9 = 0;	# show EACH VC6 source pushed

# PROGRAM VARIABLES
my $root_dir = getcwd();
my @warnings = ();
my @v6_srcs = ();  # relnm full group filter
my %v6_defs = ();
my %v6_conf = ();

# file 1 stuff
my @v6_srcs1 = ();  # relnm full group filter
my %v6_defs1 = ();
my %v6_conf1 = ();

# file 2 stuff
my @v6_srcs2 = ();  # relnm full group filter
my %v6_defs2 = ();
my %v6_conf2 = ();

#                0     1      2          3          4  5  6
#push(@v6_srcs, [$src, $ffnr, $filtname, $filttype, 0, 0, $projname] );
#push(@v6_srcs, [$src, $ffnr, $grpname, $filter,    0, 0, $proj] );
use constant {
    V6_SRC => 0,
    V6_FUL => 1,
    V6_GRP => 2,
    V6_FIL => 3,
    V6_CMP => 4,    # [4]
    V6_DON => 5,    # [5]
    V6_PRJ => 6
};

my @lines1 = ();
my @lines2 = ();
my $lncnt1 = 0;
my $lncnt2 = 0;

parse_args(@ARGV);

if (open INF1, "<$in_file1") {
	@lines1 = <INF1>;
	close INF1;
	$lncnt1 = scalar @lines1;
}

if (open INF2, "<$in_file2") {
	@lines2 = <INF2>;
	close INF2;
	$lncnt2 = scalar @lines2;
}

if ($lncnt1 && $lncnt2) {
	prt( "Loaded and scanning $lncnt1, and $lncnt2 DSP file lines ...\n" );
} else {
    prtw( "WARNING: One or both line counts is ZERO! ... $lncnt1, and $lncnt2 lines ...\n" );
}

# load FILE 1
clear_load();
process_DSP( $in_file1 );
@v6_srcs1 = @v6_srcs;  # relnm full group filter
%v6_defs1 = %v6_defs;
%v6_conf1 = %v6_conf;

# load FILE 2
clear_load();
process_DSP( $in_file2 );
@v6_srcs2 = @v6_srcs;  # relnm full group filter
%v6_defs2 = %v6_defs;
%v6_conf2 = %v6_conf;

# compare SOURCES
my $mdspcmp = 0;
$mdspcmp += compare_dsp_with_dsp($in_file1, $in_file2);
$mdspcmp += compare_cfg_of_dsp($in_file1, $in_file2);
if ($mdspcmp) {
    prt( "Some DIFFERENCES ($mdspcmp) ...\n" );
} else {
    prt("Appear NO differences ...\n");
}

show_warnings();

close_log($outfile,0);

exit($mdspcmp);
##########################################
### SUB ONLY
##########################################

sub parse_args {
	my (@av) = @_;
    my $acnt = 0;
	while (@av) {
		my $arg = shift @av;
        if ($acnt == 0) {
            $in_file1 = $arg;
        } elsif ($acnt == 1) {
            $in_file2 = $arg;
        } else {
            prt( "ERROR: Only two arguments allowed, being the two input DSP files ...\n" );
            mydie( "ABORTING!\n" );
        }
        $acnt++;
    }
}

sub comp_v1_with_v2 {
    my ($k1,$v1,$v2) = @_;
    my @a1 = space_split($v1);
    my @a2 = space_split($v2);
    my ($fnd, $i1, $i2);
    my @a1m = ();
    my $dcnt = 0;
    my $dbg_SAME = 0;
    foreach $i1 (@a1) {
        $fnd = 0;
        foreach $i2 (@a2) {
            if ($i1 eq $i2) {
                $fnd = 1;
                last;
            }
        }
        push(@a1m, $i1) if (!$fnd);
    }
    if (@a1m) {
        prt( "KEY:[$k1] Items in F1, not found in F2 ...\n" );
        foreach $i1 (@a1m) {
            prt( "$i1 " );
            $dcnt++;
        }
        prt("\n");
    } else {
        prt( "KEY:[$k1] Items in F1, not found in F2 = NONE! They are the SAME.\n" ) if ($dbg_SAME);
    }
    @a1m = ();
    foreach $i2 (@a2) {
        $fnd = 0;
        foreach $i1 (@a1) {
            if ($i1 eq $i2) {
                $fnd = 1;
                last;
            }
        }
        push(@a1m, $i2) if (!$fnd);
    }
    if (@a1m) {
        prt( "KEY:[$k1] Items in F2, not found in F1 ...\n" );
        foreach $i1 (@a1m) {
            prt( "$i1 " );
            $dcnt++;
        }
        prt("\n");
    } else {
        prt( "KEY:[$k1] Items in F2, not found in F1 = NONE! They are the SAME.\n" ) if ($dbg_SAME);
    }
    return $dcnt;
}

sub compare_cfg_of_dsp {
    my ($fil1, $fil2) = @_;
    my @done = ();
    my @keys1 = sort keys(%v6_conf1);
    my @keys2 = sort keys(%v6_conf2);
    my @dkys1 = sort keys(%v6_defs1);
    my @dkys2 = sort keys(%v6_defs2);
    my ($key1, $key2, $val1, $val2, $cnt1, $cnt2, $dcnt, $mcnt);
    $mcnt = scalar @keys1;
    $dcnt = scalar @dkys1;
    if (($mcnt == 0)&&($dcnt == 0)) {
        prtw("WARNING: No configuration compare ... File1 ALL ZERO\n");
        return 0;
    }
    $mcnt = scalar @keys2;
    $dcnt = scalar @dkys2;
    if (($mcnt == 0)&&($dcnt == 0)) {
        prtw("WARNING: No configuration compare ... File2 ALL ZERO\n");
        return 0;
    }
    prt( "F1: conf ".scalar @keys1.", defs ".scalar @dkys1."\n" );
    prt( "F2: conf ".scalar @keys2.", defs ".scalar @dkys2."\n" );
    $cnt1 = 0;
    $dcnt = 0;
    $mcnt = 0;
    foreach $key1 (@keys1) {
        $cnt1++;
        $val1 = $v6_conf1{$key1};
        if (defined $v6_conf2{$key1}) {
            $val2 = $v6_conf2{$key1};
            $dcnt += comp_v1_with_v2( $key1, $val1, $val2 );
            push(@done,$key1);
        } else {
            prt( "$cnt1: $key1 NOT IN 2 [$val1]\n" );
            $mcnt++;
        }
    }
    $cnt2 = 0;
    foreach $key2 (@keys2) {
        $cnt2++;
        $val2 = $v6_conf2{$key2};
        if (! is_in_array($key2,@done)) {
            push(@done,$key2);
            if (defined $v6_conf1{$key2}) {
                $val1 = $v6_conf1{$key2};
                $dcnt += comp_v1_with_v2( $key2, $val1, $val2 );
            } else {
                prt( "$cnt2: $key2 NOT IN 2 $val2\n" );
                $mcnt++;
            }
        }
    }

    $cnt1 = 0;
    @done = ();
    foreach $key1 (@dkys1) {
        $cnt1++;
        $val1 = $v6_defs1{$key1};
        if (defined $v6_defs2{$key1}) {
            $val2 = $v6_defs2{$key1};
            $dcnt += comp_v1_with_v2( $key1, $val1, $val2 );
            push(@done,$key1);
        } else {
            prt( "$cnt1: $key1 NOT IN 2 [$val1]\n" );
            $mcnt++;
        }
    }
    $cnt2 = 0;
    foreach $key2 (@dkys2) {
        $cnt2++;
        $val2 = $v6_defs2{$key2};
        if (! is_in_array($key2,@done)) {
            push(@done,$key2);
            if (defined $v6_defs1{$key2}) {
                $val1 = $v6_defs1{$key2};
                $dcnt += comp_v1_with_v2( $key2, $val1, $val2 );
            } else {
                prt( "$cnt2: $key2 NOT IN 2 $val2\n" );
                $mcnt++;
            }
        }
    }
    prt( "In compare of configurations of files\n" );
    show_file_stat($fil1, 1);
    show_file_stat($fil2, 2);
    if (($dcnt == 0) && ($mcnt == 0)) {
        prt( "Configurations appear EXACTLY the SAME...\n" );
    } else {
        prt( "Configurations have $dcnt differences, and $mcnt missed in one or other ...\n" );
    }
    return ($dcnt + $mcnt);
}

sub clear_load {
	@v6_srcs = ();  # relnm full group filter
	%v6_defs = ();
	%v6_conf = ();
}

sub process_DSP {
	my ($fil) = @_;
	my ($line, $prjname, $grpname, $filter, $ff, $src, $chr, $tmp, $conf, $ffnr);
	my ($itm1, $itm2, $key, $targtype);
	my $scnt = 0;
	my @dsp_lines = ();
	prt( "\nProcess DSP file $fil ... " );
    $prjname = 'UNKNOWN AT THIS POINT!';
	if ( -f $fil ) {
		prt( "already exists ...\n" );
		my ($d_name,$d_dir) = fileparse($fil);
		$d_dir = trim_all($d_dir);
		$d_dir = $root_dir if ((length($d_dir) == 0)||($d_dir eq ".\\"));
		if ( open IF, "<$fil" ) {
			@dsp_lines = <IF>;
			close IF;
			prt( "Got ".scalar @dsp_lines." lines to process ...\n" );
			my $ins = 0;
			foreach $line (@dsp_lines) {
				$line = trim_all($line);
				next if (length($line) == 0);
				$chr = substr($line, 0, 1);	# get FIRST char of LINE
				if( $chr eq '#' ) {
					# line begins with SHARP
					if ($line =~ /\s+Microsoft Developer Studio Project File - Name=\"([\.\w\s]+)+/) {
						$prjname = $1;
						prt( "Project NAME = $prjname ...\n" ) if ($dbg_dsp);
					} elsif ($line =~ /\s+Microsoft Developer Studio Generated Build File, Format Version ([\d\.]+)/) {
						prt( "MSVC Version $1 ...\n" ) if ($dbg_dsp);
					} elsif ($line =~ /\s*TARGTYPE\s+\"(.+)\"\s+/) { # Win32 (x86) Console Application" 0x0103
						$targtype = $1;
						prt( "TARGTYPE: $targtype, name=$prjname\n" );
					} elsif ($line =~ /Begin Group \"([\s\w]+)+/ ) {
						$grpname = $1;
						prt( "Begin group ... $grpname\n" ) if ($dbg_dsp);
					} elsif ($line =~ /PROP\s+Default_Filter\s+\"([\w;]+)+\"/ ) {
						$filter = $1;
						prt( "Begin Filter group $grpname, filter $filter\n" ) if ($dbg_ds8);
					} elsif ($line =~ /Begin Source File/) {
						$ins = 1;
						prt( "Begin source ... $ins ...\n" ) if ($dbg_dsp);
					} elsif ($line =~ /End Source File/) {
						$ins = 0;
						prt( "End source ... $ins ...\n" ) if ($dbg_dsp);
					} elsif ( $line =~ /ADD BASE CPP (.+)/ )  {
						# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /Yu"stdafx.h" /FD /c
						$key = 'CPP '.$conf;
						prt( "ADD BASE $key [$1]\n" ) if ($dbg_ds4);
						$v6_conf{$key} = $1;
					} elsif ( $line =~ /ADD CPP (.+)/ )  {
						# ADD CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /FD /c
						$key = 'CPP '.$conf;
						prt( "ADD $key [$1]\n" ) if ($dbg_ds4);
						$v6_conf{$key} = $1;
					} elsif ( $line =~ /ADD BASE LINK32 (.+)/ )  {
						# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /machine:I386
						$key = 'LINK '.$conf;
						prt( "ADD BASE $key [$1]\n" ) if ($dbg_ds4);
						$v6_conf{$key} = $1;
					} elsif ( $line =~ /ADD LINK32 (.+)/ )  {
						$key = 'LINK '.$conf;
						# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /machine:I386
						prt( "ADD $key [$1]\n" ) if ($dbg_ds4);
						$v6_conf{$key} = $1;
					}
				} elsif ( $chr eq '!' ) {
					if ($line =~ /^!IF\s+(.+)/i ) {
						prt( "Entering IF $1 ...\n" ) if ($dbg_ds6);
						if ($line =~ /!IF\s+(.+) == (.+)/i) {
							$itm1 = $1;
							$itm2 = $2;
							$itm1 =~ s/\"//g;
							$itm2 =~ s/\"//g;
							prt( "Got [$itm1] [$itm2]...\n" ) if ($dbg_ds6);
							if ($itm1 =~ /^\$\((.+)\)/ ) {
								if (defined $v6_defs{$1}) {
									if ($v6_defs{$1} eq $itm2) {
										$tmp = "TRUE";
									} else {
										$tmp = "FALSE";
									}
									if( $1 eq 'CFG' ) {
										$conf = $itm2;
									}
									prt( "and [$1] defined as \"$v6_defs{$1}\" ... $tmp $conf\n" ) if ($dbg_ds6);
								} else {
									prt( "NOT DEFINED [$1] ...\n" );
								}
							}
						} else {
							prt( "FAILED IF == [$line]\n" );
						}
					} elsif ( $line =~ /^!ELSE\s+/i ) {
						prt( "Entering ELSE ...\n" ) if ($dbg_ds6);
					} elsif ( $line =~ /^!ELSEIF\s+(.+)/i ) {
						prt( "Entering ELSEIF $1 ...\n" ) if ($dbg_ds6);
						if ($line =~ /!ELSEIF\s+(.+) == (.+)/i) {
							$itm1 = $1;
							$itm2 = $2;
							$itm1 =~ s/\"//g;
							$itm2 =~ s/\"//g;
							prt( "Got [$itm1] [$itm2]...\n" ) if ($dbg_ds6);
							if ($itm1 =~ /^\$\((.+)\)/ ) {
								if (defined $v6_defs{$1}) {
									if ($v6_defs{$1} eq $itm2) {
										$tmp = "TRUE";
									} else {
										$tmp = "FALSE";
									}
									if( $1 eq 'CFG' ) {
										$conf = $itm2;
									}
									prt( "and [$1] defined as \"$v6_defs{$1}\" ... $tmp $conf\n" ) if ($dbg_ds6);
								} else {
									prt( "NOT DEFINED [$1] ...\n" );
								}
							}
						} else {
							prt( "FAILED ELSEIF == [$line]\n" );
						}
					} elsif ( $line =~ /^!ENDIF\s*/i ) {
						prt( "Out ENDIF ...\n" ) if ($dbg_ds6);
					}
				} else {
                    # SOURCE=.\test.c, or
                    # SOURCE=src\FDM\YASim\YASim.hxx OR
                    # SOURCE=".\common with space\file with space.c"
					### if ($line =~ /SOURCE=([\.\\\w-:]+)+/ ) {
					###	$src = $1;
					if ($line =~ /^SOURCE=/ ) {
						$src = strip_quotes(substr($line,7));
						$ff = $d_dir.$src;
						$ffnr = fix_rel_path($ff);
						###prt( "fixed=$ffnr, src=[$src], dir=[$dir]\n" );
						if ($ins) {
							prt( "SOURCE = $src ($ff)... $ins \n" ) if ($dbg_dsp);
						} else {
							prt( "source = $src ($ff) OUTSIDE 'in source' ... $ins\n" );
						}
						if (is_c_source($src)) {
							prt("SOURCE=[$src]\n") if ($dbg_ds1);
						} elsif (is_h_source($src)) {
							prt("HEADER=[$src]\n") if ($dbg_ds2);
						} elsif (is_h_special($src)) {
							prt("HEADER=[$src]\n") if ($dbg_ds2);
						} else {
							prt("OTHER=[$src]\n") if ($dbg_ds3);
						}
						#                0     1      2          3          4  5  6
						#push(@v6_srcs, [$src, $ffnr, $filtname, $filttype, 0, 0, $projname] );
						push(@v6_srcs, [$src, $ffnr, $grpname, $filter, 0, 0, $prjname] );
						$scnt++;
						prt( "$scnt v6_srcs: $src, $ffnr, $grpname, $filter, 0, 0, $prjname\n" ) if ($dbg_ds9);
					} elsif ( $line =~ /(.*)=(.*)/ ) {
						$itm1 = $1;
						$itm2 = $2;
						$v6_defs{$itm1} = $itm2;
						prt( "Defined [$itm1] = [$itm2] ...\n" ) if ($dbg_ds5);
					} else {
						prt( "skipped [$line]\n" );
					}
				}
			}
			prt( "End DSP - got $scnt source files ...\n" );
			if ($dbg_ds7) {
				foreach $key (keys %v6_conf) {
					prt( "Config $key = [$v6_conf{$key}]\n" );
				}
			}
		} else {
			prtw( "WARNING: FAILED TO OPEN $fil FILE!\n" );
		}
	} else {
		prtw( "WARNING: $fil *** DOES NOT EXIST ***\n" );
	}
}

###############################################################################
### utitlity subs

sub compare_dsp_with_dsp {
	my ($file1,$file2) = @_;
	my ($i1, $i2, $fnd, $matched);
	my ($src1, $ff1, $fnm1, $typ1, $flg1);
	my ($src2, $ff2, $fnm2, $typ2, $flg2);
	my ($nm1, $pth1, $suf1);
	my ($nm2, $pth2, $suf2);
	my ($added, $subed, $miss1, $miss2, $min);
	my $msg = '';
    my ($moved, $numb);
    # compare SOURCES
    ###############################
	my $v6_tot1 = scalar @v6_srcs1;
	my $v6_tot2 = scalar @v6_srcs2;
    $added = 0;
    $subed = 0;	# return CHANGE counter
    if (($v6_tot1 == 0)||($v6_tot2 == 0)) {
    	prtw( "WARNING: NO compare of sources MSVC6 totals $v6_tot1, with $v6_tot2 ... when 1 or both zero\n" ); 
    	return ($added + $subed);	# return CHANGE counter
    }
	prt( "\nCompare of sources MSVC6 totals $v6_tot1, with $v6_tot2 ...\n" ); 
	$fnd = 0;
	$matched = 0;
	for ($i1 = 0; $i1 < $v6_tot1; $i1++) {
		$v6_srcs1[$i1][V6_CMP] = 0;  # clear matched
		$v6_srcs1[$i1][V6_DON] = 0;  # clear done
	}
	for ($i2 = 0; $i2 < $v6_tot2; $i2++) {
		$v6_srcs2[$i2][V6_CMP] = 0;  # clear matched
		$v6_srcs2[$i2][V6_DON] = 0;  # clear done
	}

    # for EACH in file 1
	for ($i1 = 0; $i1 < $v6_tot1; $i1++) {
		$src1 = $v6_srcs1[$i1][0];
		$ff1  = $v6_srcs1[$i1][1];
		$fnm1 = $v6_srcs1[$i1][2];
		$typ1 = $v6_srcs1[$i1][3];
		$flg1 = $v6_srcs1[$i1][V6_CMP]; # [4];
		$fnd = 0;
        ###prt( "Find [$src1] in file2\n" );
		for ($i2 = 0; $i2 < $v6_tot2; $i2++) {
			$src2 = $v6_srcs2[$i2][0];
			$ff2  = $v6_srcs2[$i2][1];
			$fnm2 = $v6_srcs2[$i2][2];
			$typ2 = $v6_srcs2[$i2][3];
			$flg2 = $v6_srcs2[$i2][V6_CMP]; # [4];
            ###prt( "Comp [$src2] file name\n" );
            ###exit(1) if ($i2 > 20);
			if ( is_same_file($src1,$src2) ) {
            # first a full compare with DIRECTORY included
			###if ( is_same_file($ff1,$ff2) ) {
				$v6_srcs2[$i2][V6_CMP] = $i1 + 1;   # put INDEX plus 1
				$v6_srcs1[$i1][V6_CMP] = $i2 + 1;
				$fnd = 1;
				last;
			}
		}
		if ($fnd) {
			$matched++;
		} else {
			#prt( "NO MATCH\n" ) if ($big_dbg);
		}
	}
	$added = $v6_tot1 - $matched;
	$subed = $v6_tot2 - $matched;
    if (($added == 0)&&($subed == 0)) {
        prt( "Sources MATCH exactly ...\n" );
    } else {
        prt( "In the compare of $file1, with $file2 ...\n" );
    	prt( "Matched $matched of $v6_tot1, with $matched of $v6_tot2 ...\n" );
    }

    # get sources NOT matched in file1
	$miss1 = 0;
    $moved = 0;
	for ($i1 = 0; $i1 < $v6_tot1; $i1++) {
		if ($v6_srcs1[$i1][V6_CMP] == 0) {
			$ff1  = $v6_srcs1[$i1][V6_FUL];
            if ( !$ignore_headers || is_c_source($ff1) ) {
                $miss1++;
                # find in file2
                for ($i2 = 0; $i2 < $v6_tot2; $i2++) {
                    if ($v6_srcs2[$i2][V6_CMP] == 0) {
                        $ff2  = $v6_srcs2[$i2][V6_FUL];
                        if ( fg_is_same_file_name($ff1,$ff2) ) {
                            $v6_srcs2[$i2][V6_DON] = $i1 + 1;   # put INDEX plus 1
                            $v6_srcs1[$i1][V6_DON] = $i2 + 1;
                            $moved++;
                            last;
                        }
                    }
                }
            }
		}
	}

	if ($miss1) {
		prt( "\nF1:$file1 contains $miss1, NOT in F2:$file2 ..." );
        prt( " but $moved moved ..." ) if ($moved);
        prt( " ignoring headers ..." ) if ($ignore_headers);
        prt( "\n" );
        $numb = 0;
		for ($i1 = 0; $i1 < $v6_tot1; $i1++) {
			if ($v6_srcs1[$i1][V6_CMP] == 0) {
				$src1 = $v6_srcs1[$i1][0];
				$ff1  = $v6_srcs1[$i1][1];
				$msg = "$src1 ";
				$min = $minlen1;
				$msg .= ' ' while (length($msg) < $min);
				$msg .= "($ff1) ";
				$min += 3 + $minlen2;
				$msg .= ' ' while (length($msg) < $min);
				if (-f $ff1) {
					$msg .= "ok";
				} else {
					$msg .= "MISSING?";
				}
                $flg1 = $v6_srcs1[$i1][V6_DON];
    			if ($flg1) {
       				$ff2  = $v6_srcs1[($flg1 - 1)][V6_FUL];
                    $msg .= " MOVED! [$ff2]";
                }
                if ( !$ignore_headers || is_c_source($ff1) ) {
                    $numb++;
                    prt( "$numb: $msg\n" );
                }
			}
		}
        prt( "Done ouput of $numb items NOT in $file2 ...\n" );
	}

    # get sources NOT matched in file2
	$miss2 = 0;
	for ($i2 = 0; $i2 < $v6_tot2; $i2++) {
		if ($v6_srcs2[$i2][V6_CMP] == 0) {
			$ff2  = $v6_srcs2[$i2][1];
            if ( !$ignore_headers || is_c_source($ff2) ) {
    			$miss2++;
            }
		}
	}
	if ($miss2) {
		prt( "\nF2:$file2 contains $miss2, NOT in F1:$file1 ...\n" );
        $numb = 0;
		for ($i2 = 0; $i2 < $v6_tot2; $i2++) {
			if ($v6_srcs2[$i2][V6_CMP] == 0) {
				$src2 = $v6_srcs2[$i2][0];
				$ff2  = $v6_srcs2[$i2][1];
				$msg = "$src2 ";
				$min = $minlen1;
				$msg .= ' ' while (length($msg) < $min);
				$msg .= "($ff2) ";
				$min += 3 + $minlen2;
				$msg .= ' ' while (length($msg) < $min);
				if (-f $ff2) {
					$msg .= "ok";
				} else {
					$msg .= "MISSING?";
				}
                $flg2 = $v6_srcs2[$i2][V6_DON];
    			if ($flg2) {
                    $ff1 = $v6_srcs1[($flg2 - 1)][V6_FUL];
                    $msg .= " MOVED! [$ff1]";
                }
                if ( !$ignore_headers || is_c_source($ff2) ) {
                    $numb++;
                    prt( "$numb: $msg\n" );
                }
			}
		}
        prt( "Done ouput of $numb items NOT in $file1 ...\n" );
	}
	prt("\n");

    if ($also_show_matched) {
		prt( "\n$file1 list of MATCHED to $file2 ... ".($v6_tot1 - $miss1)." items ...\n" );
        $numb = 0;
    	for ($i1 = 0; $i1 < $v6_tot1; $i1++) {
    		$flg1 = $v6_srcs1[$i1][V6_CMP]; # [4];
	    	if ($flg1 > 0) {
				$ff1  = $v6_srcs1[$i1][V6_FUL];
				$ff2  = $v6_srcs2[($flg1 - 1)][V6_FUL];
				$msg = "$ff1 ";
				$min = $minlen1;
				$msg .= ' ' while (length($msg) < $min);
				$msg .= "$ff2 ";
				$min += 3 + $minlen2;
				$msg .= ' ' while (length($msg) < $min);
				if (-f $ff1) {
					$msg .= "ok";
				} else {
					$msg .= "MISSING?";
				}
                if ( !$ignore_headers || is_c_source($ff1) ) {
                    $numb++;
                    prt( "$numb: $msg\n" );
                }
            }
        }
        prt( "Done ouput of $numb items MATCHED ...\n" );
    }

    if (($added == 0)&&($subed == 0)) {
    	return ($added + $subed);	# return CHANGE counter
    }

    if ($also_show_moved) {
		prt( "\n$file1 list of MOVED in $file2 ... $moved items ...\n" );
        $numb = 0;
    	for ($i1 = 0; $i1 < $v6_tot1; $i1++) {
    		$flg1 = $v6_srcs1[$i1][V6_DON]; # [4];
	    	if ($flg1 > 0) {
				$ff1  = $v6_srcs1[$i1][V6_FUL];
				$ff2  = $v6_srcs2[($flg1 - 1)][V6_FUL];
				$msg = "$ff1 ";
				$min = $minlen1;
				$msg .= ' ' while (length($msg) < $min);
				$msg .= "$ff2 ";
				$min += 3 + $minlen2;
				$msg .= ' ' while (length($msg) < $min);
				if (-f $ff1) {
					$msg .= "ok";
				} else {
					$msg .= "MISSING?";
				}
                if ( !$ignore_headers || is_c_source($ff1) ) {
                    $numb++;
                    prt( "$numb: $msg\n" );
                }
            }
        }
        prt( "Done ouput of $numb items MOVED ...\n" );
    }

	return ($added + $subed);	# return CHANGE counter
}

sub fg_is_same_file_name {
	my ($f1, $f2) = @_;
    my ($f1n,$f1d,$f1e) = fileparse($f1, qr/\.[^.]*/ );
    my ($f2n,$f2d,$f2e) = fileparse($f2, qr/\.[^.]*/ );
    if ( (lc($f1n) eq lc($f2n)) && (lc($f1e) eq lc($f2e))) {
        return 1;
    }
    return 0;
}

sub is_same_file {
	my ($f1, $f2) = @_;
	my $len1 = length($f1);
    my $len2 = length($f2);
	$f1 =~ s/\//\\/g;
	$f2 =~ s/\//\\/g;
	my $lcf1 = lc($f1);
	my $lcf2 = lc($f2);
    my $ch1 = '';
    my $ch2 = '';
	if ($len1 != $len2) {
        ###prt( "NOT SAME LENGTH [$f1]($len) vs [$f2]($len2)\n" );
        # but what about comparing -
        # src\AIModel\submodel.cxx
        # C:\FGCVS\FlightGear\source\src\AIModel\submodel.cxx
        my ($i1, $i2, $hadsep);
        $i1 = $len1 - 1;
        $i2 = $len2 - 1;
        $hadsep = 0;
        while ($i1 && $i2) {
            $ch1 = substr($lcf1,$i1,1);
            $ch2 = substr($lcf2,$i2,1);
    		if ($ch1 ne $ch2) {
                ##prt( "FAILED at char $i1:$i2: $ch1 vs $ch2 [$f1]($len1) & [$f2]($len2)\n" );
		    	return 0;
		    }
            $hadsep++ if ($ch1 eq "\\");
            $i1--;
            $i2--;
        }
		return 1 if ($hadsep);	# is the SAME TAIL
        return 0;
	}
	my $i = 0;
	while ($i < $len1) {
        $ch1 = substr($lcf1,$i,1);
        $ch2 = substr($lcf2,$i,1);
		if ($ch1 ne $ch2) {
            ###prt( "FAILED at char ".($i + 1)." $ch1 vs $ch2 [$f1]($len1) & [$f2]($len2)\n" );
			return 0;
		}
		$i++;
	}
	return 1;   # they ARE the SAME
}

# extracted from utils.pl
sub unix_2_dos {
	my ($f) = shift;
	$f =~ s/\//\\/g;
	return $f;
}

sub sub_common_folder {
	my ($f1, $f2) = @_;
	my $off = 0;
	my $df1 = lc(unix_2_dos($f1));
	my $df2 = lc(unix_2_dos($f2));
	while ( substr($df1,$off,1) && substr($df2,$off,1) &&
			( substr($df1,$off,1) eq substr($df2,$off,1) ) ) {
		$off++;
	}
	return substr($f1,$off);
}

sub prtw {
    my ($tx) = shift;
    if ($tx =~ /\n$/) {
        prt($tx);
        $tx =~ s/\n$//;
    } else {
        prt("$tx\n");
    }
    push(@warnings,$tx);
}

sub show_warnings {
    if (@warnings) {
        prt( "\nGot ".scalar @warnings." WARNINGS ...\n" );
        foreach my $line (@warnings) {
            prt("$line\n" );
        }
        prt("\n");
    } else {
        prt("\nNo warnings issued.\n\n");
    }
}

# eof - fgcmp2dsps.pl

# WHY THESE ???
# 1: src\GUI\SafeTexFont.cxx                 (FlightGear\src\GUI\SafeTexFont.cxx)         is ok
# appear this SHOULD be added

# 2: src\Main\fg_os_osgviewer.cxx            (FlightGear\src\Main\fg_os_osgviewer.cxx)                       ok
# AND
# FlightGear\FlightGear.dsp contains 95, NOT in tempscan.dsp ...
# 1: src\Main\fg_os.cxx                      (FlightGear\src\Main\fg_os.cxx)                                 ok
# ok, this is a problem deciding, SDL, GLUT, or OSG-viewer - from src/Main/Makefile.am
#if USE_SDL
#GFX_CODE = fg_os_sdl.cxx $(GFX_COMMON)
#else
#if USE_GLUT
#GFX_CODE = fg_os.cxx $(GFX_COMMON)
#else
#GFX_CODE = fg_os_osgviewer.cxx $(GFX_COMMON)
#endif
#endif

# 3: src\Network\jpg-httpd.cxx               (FlightGear\src\Network\jpg-httpd.cxx)                          ok
# decision to ADD, from src/Network/Makefile.am
#if ENABLE_JPEG_SERVER
#JPEG_SERVER = jpg-httpd.cxx jpg-httpd.hxx
#else
#JPEG_SERVER =
#endif

# 4: src\FDM\SP\Balloon.cxx                  (FlightGear\src\FDM\SP\Balloon.cxx)                             ok
# 5: src\FDM\SP\BalloonSim.cpp               (FlightGear\src\FDM\SP\BalloonSim.cpp)                          ok
# 6: src\FDM\SP\MagicCarpet.cxx              (FlightGear\src\FDM\SP\MagicCarpet.cxx)                         ok
# hmmm, these are in src\FDM\SP\Makefile.am
# The makefile is READ, WHY NOT ADDED??? fgamscan.pl read this makefile, and extracted the sources
# LIBRARY [libSPFDM_a] has SOURCES [src\FDM\SP\ADA.cxx src\FDM\SP\ADA.hxx src\FDM\SP\ACMS.cxx 
# src\FDM\SP\ACMS.hxx src\FDM\SP\Balloon.cxx src\FDM\SP\Balloon.h src\FDM\SP\BalloonSim.cpp 
# src\FDM\SP\BalloonSim.h src\FDM\SP\MagicCarpet.cxx src\FDM\SP\MagicCarpet.hxx]
# so OK, THEY SHOULD BE ADDED, so fgamscan.pl IS CORRECT, producing a BETTER DSP file.
