#!/perl -w
# NAME: showdsp.pl
# AIM: Read in a DSW/DSP file, and show results
# 04/04/2012 - Specific switch for specific shows
# 17/10/2010 - More enhancements... like if NO sources
# 01/06/2010 - Lots of enhancements...
# 01/05/2010 geoff mclane http://geoffair.net/mperl
use strict;
use warnings;
use File::Basename;  # split path ($name,$dir,$ext) = fileparse($file [, qr/\.[^.]*/] )
use File::stat; # to get the file date
use File::Spec; # File::Spec->rel2abs($rel); # we are IN the SLN directory, get ABSOLUTE from RELATIVE
use Cwd;        # to set root
unshift(@INC, 'C:/GTools/perl');
#### require 'logfile.pl' or die "Unable to load logfile.pl ...\n";
#### require 'fgdsphdrs03.pl' or die "Unable to load fgdsphdrs03.pl ...\n";
#### require 'scanvc.pl' or die "Unable to load scanvc.pl ...\n";
require 'lib_utils.pl' or die "Unable to load 'lib_utils.pl'! Check location and \@INC content.\n";
require 'lib_dspscan.pl' or die "Unable to load 'lib_dspscan.pl'! Check location and \@INC content.\n";
require 'lib_dsphdrs.pl' or die "Unable to load 'lib_dsphdrs.pl'! Check location and \@INC content.\n";
require 'lib_vcscan.pl' or die "Unable to load 'lib_vcscan.pl'! Check location and \@INC content.\n";
# log file stuff
my $perl_base = "C:\\GTools\\perl"; # perl directory
my ($LF);
my $pgmname = $0;
if ($pgmname =~ /\w{1}:\\.*/) {
    my @tmpsp = split(/\\/,$pgmname);
    $pgmname = $tmpsp[-1];
}
my $outfile = $perl_base."\\temp.$pgmname.txt";
open_log($outfile);

# options
my $my_version = '0.0.4 2012-04-04';
# my $my_version = '0.0.3 2010-10-17';
my $load_log = 0;   # -l to set
my $verbose = 0;
my $dbg_write = 0;
my $tmpout = $perl_base."\\tempsd.dsp";
my $write_dsp_file = 0;
my $show_source = 0;
my $show_configs = 0;
my $show_definitions = 0;
my $test_libs = 1;

my $minlen1 = 40;
my $minlen2 = 64;

# debug
my $dbg_ds4 = 0;    # show CPP and LINK config items - %v6_conf
my $dbg_ds5 = 0;    # show Defined items
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
my $dbg_ds10 = 0; # show prt( "NO MATCH of 1 [$ff1] in 2\n" ) if ($dbg_ds10);
my $dbg_ds11 = 0; # prt("Doing switch hashes... src[$src]\n" ) if ($disp && $dbg_ds11); and end as well
my $dbg_ds12 = 0;
my $dbg_ds13 = 0; # prt("LIBS: for [$ccfg] = [$val]\n") if ($dbg_ds13);
my $dbg_ds14 = 0; # show ' Changed '
my $dbg_ds15 = 0; # show DEF and INC lists
my $dbg_ds16 = 0;

sub set_debug_items($) {
    my $v = shift;
    $dbg_ds4 = $v; $dbg_ds5 = $v; $dbg_ds6 = $v; $dbg_ds7 = $v; $big_dbg = $v; $dbg_ds8 = $v;
    $dbg_ds9 = $v; $dbg_ds10 = $v; $dbg_ds11 = $v; $dbg_ds12 = $v;
}

sub set_debug_on() { set_debug_items(1); }
sub set_debug_off() { set_debug_items(0); }

sub set_all_debug($) {
    my ($val) = shift;
    set_debug_on();
    $load_log = 1;
    $verbose = 9;
    if ($val) {
        $dbg_write = -1;
        set_load_debug_on();
    }
}

my @warnings = ();

my @system_libs = qw(kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib 
ole32.lib oleaut32.lib uuid.lib ws2_32.lib);

my @link_options = qw(/libpath: /nologo /subsystem: /machine: /out:);

sub is_system_lib($) {
    my $lib = shift;
    my $lclib = lc($lib);
    my ($tst);
    foreach $tst (@system_libs) {
        return 1 if ($lclib eq $tst);
    }
    return 0;
}

my $in_file1 = '';
#my $in_file1 = 'C:\Projects\gtk+-2.22.0\temp\temp.libgdk_quartz_2_0.dsp';
#my $in_file1 = 'C:\Projects\fltk-1.3\ide\MSVC\tile.dsp';
#my $in_file1 = 'temp.testcon.dsp';
#my $in_file1 = 'C:\GTools\tools\Spy5\Spy5.dsp';
my $root_dir = cwd();   # 09/03/2010 - was just '.'; which gives wanings from 'rel' function
my $projname = 'UNKNOWN';


sub VERB1() { return ($verbose > 0); }
sub VERB2() { return ($verbose > 1); }
sub VERB3() { return ($verbose > 2); }
sub VERB5() { return ($verbose > 4); }
sub VERB9() { return ($verbose > 8); }

sub prtw($) {
    my ($tx) = shift;
    $tx =~ s/\n$//;
    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("No warnings issued.\n");
    }
}

sub pgm_exit($$) {
    my ($val,$msg) = @_;
    show_warnings();
    #my $dbs = get_dbg_stg();
    #if (length($dbs)) {
    #    prt("WARNING: Debug is ON for [$dbs], in fgscanvc03.pl\n" );
    #}
    if (length($msg)) {
        $msg .= "\n" if ( !($msg =~ /\n$/) );
        prt($msg);
    }
    close_log($outfile,$load_log);
    # unlink($outfile);   # delete output file
    exit($val);
}

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

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

### utitlity subs

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 sd_get_nn($) { # perl nice number nicenum add commas
	my ($n) = shift;
	if (length($n) > 3) {
		my $mod = length($n) % 3;
		my $ret = (($mod > 0) ? substr( $n, 0, $mod ) : '');
		my $mx = int( length($n) / 3 );
		for (my $i = 0; $i < $mx; $i++ ) {
			if (($mod == 0) && ($i == 0)) {
				$ret .= substr( $n, ($mod+(3*$i)), 3 );
			} else {
				$ret .= ',' . substr( $n, ($mod+(3*$i)), 3 );
			}
		}
		return $ret;
	}
	return $n;
}

sub sd_get_YYYYMMDD($) {
    my ($t) = shift;
    my @f = (localtime($t))[0..5];
    my $m = sprintf( "%04d/%02d/%02d",
        $f[5] + 1900, $f[4] +1, $f[3]);
    return $m;
}


sub show_dsp_rh($) {
    my ($rh) = @_;
    my ($key,$val,$k2,$v2,$cnt,$i);
    my ($src,$ffn,$grp,$flt,$ok,$mink,$len);
    my (@arr,$tmp,$cnt2,$itm);
    my ($ff,$lib,$fnd);
    my %configs = ();
    if (! defined ${$rh}{'FILE_NAME'}) {
        pgm_exit(1,"ERROR: Ref hash does NOT contain 'FILE_NAME'!\n");
    }
    my $file_name = ${$rh}{'FILE_NAME'};
    my ($fname,$fdir) = fileparse($file_name);
    my ($n,$d);
    foreach $key (keys %{$rh}) {
        $val = ${$rh}{$key};
        if ($key =~ /^FILE_/) {
            if ($key eq 'FILE_TIME') {
                prt("Key [$key] = [".sd_get_YYYYMMDD($val)."] ($val)\n") if (VERB9());
            } elsif ($key eq 'FILE_SIZE') {
                prt("Key [$key] = [".sd_get_nn($val)."] bytes\n") if (VERB9());
            } elsif ($key eq 'FILE_NAME') {
                prt("Key [$key] = [$val]\n") if (VERB9());
            } else {
                prt("Key [$key] = [$val]\n") if (VERB9());
            }
        } else {
            if ($key eq 'SOURCES') {
                # push(@{$rsrcs}, [$src, $ffnr, $grpname, $filter, 0, 0, $proj] );
                $cnt = scalar @{$val};
                prt("Key [$key] Count $cnt\n");
                $mink = 0;
                for ($i = 0; $i < $cnt; $i++) {
                    $src = ${$val}[$i][0];
                    $len = length($src);
                    $mink = $len if ($len > $mink);
                }
                for ($i = 0; $i < $cnt; $i++) {
                    $src = ${$val}[$i][0];
                    $ffn = ${$val}[$i][1];
                    $grp = ${$val}[$i][2];
                    $flt = ${$val}[$i][3];
                    $ok = 'NF';
                    $ok = 'ok' if (-f $ffn);
                    $src .= ' ' while (length($src) < $mink);
                    prt( " src=[$src] [$grp] [$flt] $ok\n") if (VERB9() || $show_source);
                }
            } elsif ($key eq 'CONFIGS') {
                # $key = 'CPP '.$conf;
                # prt( "dbg_ds4: ADD BASE key=[$key] [$item]\n" ) if ($dbg_ld_04);
                # ${$rconf}{$key} = $item;
                $mink = 0;
                $cnt = 0;
                foreach $k2 (keys %{$val}) {
                    $len = length($k2);
                    $mink = $len if ($len > $mink);
                    $cnt++;
                    @arr = split('-',$k2);
                    $tmp = trim_all($arr[-1]);
                    if (defined $configs{$tmp}) {
                        $configs{$tmp}++;
                    } else {
                        $configs{$tmp} = 1;
                    }
                }
                $cnt2 = scalar keys(%configs);
                prt("Key [$key] Count $cnt. $cnt2 different.\n");
                if (VERB2() || $show_configs) {
                    if (VERB5()) {
                        my @syslibs = ();
                        my @libpaths = ();
                        my @otherlibs = ();
                        foreach $k2 (keys %{$val}) {
                            $v2 = ${$val}{$k2};
                            if ($k2 =~ /^LINK\s+/) {
                                #prt("$k2\n");
                                @arr = space_split($v2);
                                foreach $itm (@arr) {
                                    if (is_system_lib($itm)) {
                                        #push(@syslibs,$itm);
                                    } elsif ($itm =~ /^\/libpath:(.+)/) {
                                        $tmp = strip_quotes($1);
                                        push(@libpaths,$tmp);
                                        #prt("OPTIONS: $itm\n");
                                    } else {
                                        #prt("ITEM: $itm\n");
                                        if ($itm =~ /\.lib$/i) {
                                            push(@otherlibs,$itm);
                                        }
                                    }
                                }
                            }
                        }
                        foreach $k2 (keys %{$val}) {
                            $v2 = ${$val}{$k2};
                            if ($k2 =~ /^LINK\s+/) {
                                prt("$k2\n");
                                @arr = space_split($v2);
                                foreach $itm (@arr) {
                                    if (is_system_lib($itm)) {
                                        push(@syslibs,$itm);
                                    } elsif ($itm =~ /^\//) {
                                        prt("OPTIONS: $itm\n");
                                    } else {
                                        if ($itm =~ /\.lib$/i) {
                                            # push(@otherlists,$itm);
                                        } else {
                                            prt("ITEM: $itm\n");
                                        }
                                    }
                                }
                                prt("SYS.LIBS: ".join(" ",@syslibs)."\n") if (@syslibs);
                                if (@otherlibs) {
                                    if (VERB5() || $test_libs) {
                                        $cnt = scalar @otherlibs;
                                        prt("Other LIBS count $cnt\n");
                                        $fnd = "FILE NOT FOUND";
                                        $ok = "NO DIRECTORY";
                                        foreach $lib (@otherlibs) {
                                            if (@libpaths) {
                                                foreach $itm (@libpaths) {
                                                    if ($itm =~ /\.\./) {
                                                        # is relative
                                                        $ff = $fdir;
                                                        $ff .= $itm;
                                                    } else {
                                                        $ff = $itm;
                                                    }
                                                    $ff .= "\\" if ( !($itm =~ /(\\|\/)$/) );
                                                    $ff .= $lib;
                                                    $ff = fix_rel_path3($ff,"showdsp");
                                                    $ffn = $ff;
                                                    ($n,$d) = fileparse($ffn);
                                                    if (-d $d) {
                                                        $ok = "dok";
                                                    }
                                                    if (-f $ffn) {
                                                        $fnd = "ok";
                                                        last;
                                                    }
                                                }
                                            } else {
                                                $ff = $fdir;
                                                $ff .= $lib;
                                                $ff = fix_rel_path3($ff,"showdsp");
                                                $ffn = $ff;
                                                ($n,$d) = fileparse($ffn);
                                                if (-d $d) {
                                                    $ok = "dok";
                                                }
                                                if (-f $ffn) {
                                                    $fnd = "ok";
                                                }
                                            }
                                            # if ($fnd ne 'ok') {
                                            # }
                                            prt("$ffn $ok $fnd\n");
                                        }
                                    } else {
                                        prt("Other LIBS: ".join(" ",@otherlibs)."\n");
                                    }
                                }
                            } else {
                                $k2 .= ' ' while (length($k2) < $mink);
                                prt("  $k2 = [$v2]\n");
                            }
                        }
                    } else {
                        foreach $k2 (keys %{$val}) {
                            $v2 = ${$val}{$k2};
                            $k2 .= ' ' while (length($k2) < $mink);
                            prt("  $k2 = [$v2]\n");
                        }
                    }
                }
            } elsif ($key eq 'DEFINITIONS') {

#                # ${$rdefs}{'PROJECT_NAME'} = $prjname;
#                # prt( "TARGTYPE: [$targtype], name=[$prjname] ($proj)\n" );
#                # ${$rdefs}{'PROJECT_TYPE'} = $targtype;
#                #### # ADD CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /FD /c
#                # $key = 'CPP '.$conf;
#                # prt( "dbg_ds4: ADD key=[$key] [$item]\n" ) if ($dbg_ld_04);
#                # ${$rdefs}{$key} = $item;

                $mink = 0;
                $cnt = 0;
                foreach $k2 (keys %{$val}) {
                    $len = length($k2);
                    $mink = $len if ($len > $mink);
                    $cnt++;
                }
                prt("Key [$key] Count $cnt\n");
                foreach $k2 (keys %{$val}) {
                    $v2 = ${$val}{$k2};
                    $k2 .= ' ' while (length($k2) < $mink);
                    prt("  $k2 = [$v2]\n") if (VERB2() || $show_definitions);
                }
            } else {
                prtw("WARNING: New KEY added, not yet handled!\n");
            }
        }
    }
}

sub collect_per_option($$) {
    my ($val,$opt) = @_;
    my @arr = space_split($val);
    my $len = scalar @arr;
    my ($i,$itm);
    my $list = '';
    my %hash = ();
    for ($i = 0; $i < $len; $i++) {
        $itm = $arr[$i];
        if ($itm eq $opt) {
            $i++;
            if ($i < $len) {
                $list = strip_quotes($arr[$i]);
                if (defined $hash{$list}) {
                    $hash{$list}++;
                } else {
                    $hash{$list} = 1;
                }
            }
        }
    }
    return \%hash;
}

# /I "." /I "..\..\zlib" /I "..\..\png" /I "..\..\jpeg" /I "../.."
sub get_include_list($) {
    my ($val) = shift;
    return collect_per_option($val,'/I');
}

sub get_runtime_opt($) {
    my ($val) = shift;
    my @arr = space_split($val);
    foreach my $itm (@arr) {
        return $itm if ($itm =~ /^\/M\w+d*$/);
    }
    return "";
}

# /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" 
# /D "_CRT_SECURE_NO_DEPRECATE" /D "WIN32_LEAN_AND_MEAN" /D "VC_EXTRA_LEAN" /D "WIN32_EXTRA_LEAN"
sub get_defined_list($) {
    my ($val) = shift;
    return collect_per_option($val,'/D');
}

sub add_def_defines($) {
    my ($rh) = shift;
    my %def_defines = (
        'WIN32' => 1,
        '_DEBUG' => 2,
        '_WINDOWS' => 3,
        '_MBCS' => 4,
        'NDEBUG' => 5,
        'DLL' => 6,
        'CONSOLE' => 7
    );
    foreach my $itm (keys %def_defines) {
        ${$rh}{$itm} = -1;
    }
}

sub add_def_libraries($) {
    my ($rh) = @_;
    # maybe comctl32.lib
    my @def_libraries = qw( kernel32.lib user32.lib gdi32.lib winspool.lib
        comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib);
    foreach my $itm (@def_libraries) {
        ${$rh}{$itm} = -1;
    }
}

sub get_vclike_ref_from_dsp_ref($$$) {
    my ($rdsp,$inf,$rok) = @_;
    my $rh = get_default_ref_hash($inf);
    my $chkcnt = 0;
    my $pass = 2;
    my ($rdefs,$rsrcs,$scnt,$i,$src,$ff,$grp,$flt);
    my ($key,$keyin,$keyout,$val,@src,$proj,$cfg,$ptyp,@cfgs,$ccnt,$dbg);
    my ($ccfg,$cnam,$dsp_sub_sub,$ptyp2,$lnk,$prp,$tcnt,$ok,$rcfgs);
    $keyout = 'PROJECT_NAME';
    $keyin  = 'DEFINITIONS';
    $ok = 0;
    if (defined ${$rdsp}{$keyin}) {
        $rdefs = ${$rdsp}{$keyin};
        $key = $keyout;
        if (defined ${$rdefs}{$key}) {
            $proj =  ${$rdefs}{$key};
            ${$rh}{$keyout} = $proj;
            $chkcnt++;
        } else {
            prt("No 'PROJECT_NAME' in extract 'DEFINITIONS' ref hash!\n");
            return $rh;
        }
        $key = 'PROJECT_TYPE'; # = [Win32 (x86) Application]
        # if ( get_app_type_4_short($tmp,\$curr_app_type)  && length($curr_app_type) ) {

        if (defined ${$rdefs}{$key}) {
            $ptyp =  ${$rdefs}{$key};
            #prt("Finding APP_TYPE from [$ptyp]\n");
            my $ttr = get_targ_type_ref();
            $ptyp2 = "NOT FOUND";
            foreach $key (keys %{$ttr}) {
                $val = ${$ttr}{$key};   # like '# TARGTYPE "Win32 (x86) Console Application" 0x0103'
                $val =~ s/^#\s+TARGTYPE\s+"//;
                $val =~ s/"\s0x\d+\s*//;
                #prt(" Comparing with [$val]...\n");
                if ($val eq $ptyp) {
                    $ptyp2 = $key;
                    ${$rh}{'APP_TYPE'} = $key;
                    last;
                }
            }
        } else {
            prt("No 'PROJECT_TYPE' in extract 'DEFINITIONS' ref hash!\n");
            return $rh;
        }
        $ok = 1;
    }
    $keyin = 'CONFIGS';
    $ok = 0;
    if (defined ${$rdsp}{$keyin}) {
        $rcfgs = ${$rdsp}{$keyin};
        $ok = 1;
    } else {
        prt("No 'CONFIGS' in ref hash!\n");
        return $rh;
    }
    my %hash = ();
    my $var1 = "-NEW_OUTD-";
    my $var2 = "-NEW_INTER-";
    my ($inclist,$deflist,$rtopt,$cur,$k2,$rcur,$ncur,$nitm);
    my ($var);
    # Now not sure now why some in 'CONFIGS' and some in 'DEFINITIONS' - looks like they could be in ONE
    # so here FOLD them into ONE
    foreach $key (keys %{$rdefs}) {
        $val = ${$rdefs}{$key};
        if (defined $hash{$key}) {
            $var = $hash{$key};
            if ($var ne $val) {
                pgm_exit(1,"ERROR: Key [$key] already defined\n[$var], now as\n[$val] WHAT IS DIFF?\n");
            }
        } else {
            $hash{$key} = $val;
        }
    }
    foreach $key (keys %{$rcfgs}) {
        $val = ${$rcfgs}{$key};
        if (defined $hash{$key}) {
            $var = $hash{$key};
            if ($var ne $val) {
                pgm_exit(1,"ERROR: Key [$key] already defined\n[$var], now as\n[$val] WHAT IS DIFF?\n");
            }
        } else {
            $hash{$key} = $val;
        }
    }

    my %cfg_hash = ();
    if ($ok) {
        # =======================================================
        $rdefs = \%hash;    # Use the SINGLE set of defininitions
        # =======================================================
        prt("Set 'PROJECT_NAME' to [$proj], type [$ptyp] [$ptyp2]\n") if (VERB9());
        # CPP tile - Win32 Debug          = [/nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /Yu"stdafx.h" /FD /GZ /c]
        $cfg = "CPP\\s+$proj\\s+-\\s+Win32\\s+";
        # LINK tile - Win32 Debug         = [kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib fltkd.lib comctl32.lib /libpath:"..\..\lib" /nodefaultlib:"libcd" /nologo /subsystem:windows /debug /machine:I386 /pdbtype:sept /out:../../test/tiled.exe]
        $lnk = "LINK\\s+$proj\\s+-\\s+Win32\\s+";
        # PROP tile - Win32 Debug -NEW_OUTD- = [tile_]
        $prp = "PROP\\s+$proj\\s+-\\s+Win32\\s+";
        @cfgs = ();
        $ccnt = 0;
        $var = 0;
        $tcnt = 0;
        # feed on the single COMBINED hash
        foreach $key (keys %{$rdefs}) {
            $tcnt++;
            $val = ${$rdefs}{$key};
            $ccfg = '';
            if ($key =~ /^$cfg(.+)$/) {
                $cnam = $1;
                $dbg = 0;
                $dbg = 1 if ($cnam =~ /Debug/i);
                $ccfg = "$cnam|Win32";
                $var++;
            } elsif ($key =~ /^$lnk(.+)$/) {
                $cnam = $1;
                $dbg = 0;
                $dbg = 1 if ($cnam =~ /Debug/i);
                $ccfg = "$cnam|Win32";
                $var++;
            } elsif ($key =~ /^$prp(.+)\s+([\s-]+)$/) {
                $cnam = $1;
                $dbg = 0;
                $dbg = 1 if ($cnam =~ /Debug/i);
                $ccfg = "$cnam|Win32";
                $var++;
            } elsif ($key =~ /^$proj\s+Win32\s+(.+)\s*/) {
                $cnam = $1;
                $dbg = 0;
                $dbg = 1 if ($cnam =~ /Debug/i);
                $ccfg = "$cnam|Win32";
                $var++;
            }
            if (length($ccfg)) {
                if (! defined $cfg_hash{$ccfg}) {
                    $cfg_hash{$ccfg} = get_default_sub3($dbg);
                    $ccnt++;
                    prt("CFG:$ccnt: [$ccfg]\n") if (VERB9());
                }
            }
        }
        prt("DEFINITIONS: Of $tcnt hash keys, found $var config types, getting $ccnt diferent configs.\n") if (VERB9());
        $ccnt = 0;
        # *TBD*  "-NEW_POST-"     => "",
        # feed on the single COMBINED hash
        foreach $key (keys %{$rdefs}) {
            $val = ${$rdefs}{$key};
            #prt("CFG: $key = [$val]\n");
            if ($key =~ /^$cfg(.+)$/) {
                # deal with CONFIG ITEMS
                $cnam = $1;
                $dbg = 0;
                $dbg = 1 if ($cnam =~ /Debug/i);
                $ccfg = "$cnam|Win32";
                #$dsp_sub_sub = get_default_sub3($dbg);
                if (! defined $cfg_hash{$ccfg}) {
                    pgm_exit(1,"ERROR: Internal [$ccfg] NOT DEFINED!\n");
                }
                $dsp_sub_sub = $cfg_hash{$ccfg};
                # value = [/nologo /W3 /MDd /Gm /GR /GX /ZI /Od
                $rtopt = get_runtime_opt($val);
                # prt("CFG: $key = [$val] RT=[$rtopt]\n");
                $k2 = '-NEW_RT-'; # "/MT" is default,
                # ${$rds}{"-NEW_RT-"}    = '/MT';
                #        ${$rds}{"-NEW_RT-"}    = '/MTd';
                if (defined ${$dsp_sub_sub}{$k2}) {
                    $cur = ${$dsp_sub_sub}{$k2};
                    if ($cur ne $rtopt) {
                        ${$dsp_sub_sub}{$k2} = $rtopt;
                        prt(" Changed RT:$k2: from [$cur] to [$rtopt]\n") if ($dbg_ds14);
                    } else {
                        prt(" No change RT:$k2: from [$cur]\n") if ($dbg_ds14);
                    }
                } else {
                    prtw("WARNING: NOT DEFINED RT:$k2!\n");
                }

                # /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_CRT_SECURE_NO_DEPRECATE" /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "WIN32_LEAN_AND_MEAN" /D "VC_EXTRA_LEAN" /D "WIN32_EXTRA_LEAN"
                $deflist = get_defined_list($val);
                prt("DEF: [".join(" ", (sort keys(%{$deflist})))."]\n") if ($dbg_ds15);
                $k2 = "-NEW_DEFS-"; # "/D \"_CRT_SECURE_NO_WARNINGS\"",
                if (defined ${$dsp_sub_sub}{$k2}) {
                    $cur = ${$dsp_sub_sub}{$k2};
                    $rcur = get_defined_list($cur);
                    add_def_defines($rcur);
                    $ncur = '';
                    foreach $nitm (keys %{$deflist}) {
                        if (! defined ${$rcur}{$nitm}) {
                            $ncur .= ' ' if (length($cur));
                            $ncur .= "/D \"$nitm\"";
                        }
                    }
                    if (length($ncur)) {
                        prt( " Changed DF:$k2: from [$cur], adding [$ncur]") if ($dbg_ds14);
                        $cur .= ' ' if (length($cur));
                        $cur .= $ncur;
                        ${$dsp_sub_sub}{$k2} = $cur;
                        prt( " to [$cur]\n") if ($dbg_ds14);
                    } else {
                        prt( " NO change DF:$k2: from [$cur]\n") if ($dbg_ds14);
                    }
                } else {
                    prtw("WARNING: NOT DEFINED DF:$k2!\n");
                }

                # /I "." /I "..\..\zlib" /I "..\..\png" /I "..\..\jpeg" /I "../.."
                $inclist = get_include_list($val);
                prt("INC: [".join(" ", (sort keys(%{$inclist})))."]\n") if ($dbg_ds15);
                $k2 = "-NEW_INCS-"; # => "",
                if (defined ${$dsp_sub_sub}{$k2}) {
                    $cur = ${$dsp_sub_sub}{$k2};
                    $rcur = get_include_list($cur);
                    $ncur = '';
                    foreach $nitm (keys %{$inclist}) {
                        if ( ! defined ${$rcur}{$nitm}) {
                            $ncur .= ' ' if (length($cur));
                            $ncur .= "/I \"$nitm\"";
                        }
                    }
                    if (length($ncur)) {
                        prt( " Changed IN:$k2: from [$cur], adding [$ncur]") if ($dbg_ds14);
                        $cur .= ' ' if (length($cur));
                        $cur .= $ncur;
                        ${$dsp_sub_sub}{$k2} = $cur;
                        prt( " to [$cur]\n") if ($dbg_ds14);
                    } else {
                        prt( " NO change IN:$k2: from [$cur]\n") if ($dbg_ds14);
                    }
                } else {
                    prtw("WARNING: NOT DEFINED IN:$k2!\n");
                }
                push(@cfgs,[$cnam, $var1, $ccfg, $dsp_sub_sub]);
                $ccnt++;
                prt("Config $ccnt: [$cnam] [$var1] [$ccfg] [$dbg]\n") if ($dbg_ds16);
            } elsif ($key =~ /^$lnk(.+)$/) {
                $cnam = $1;
                $dbg = 0;
                $dbg = 1 if ($cnam =~ /Debug/i);
                $ccfg = "$cnam|Win32";
                if (! defined $cfg_hash{$ccfg}) {
                    pgm_exit(1,"ERROR: Internal [$ccfg] NOT DEFINED!\n");
                }
                $dsp_sub_sub = $cfg_hash{$ccfg};
                # like [Debug|Win32] = [kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib fltkd.lib comctl32.lib /libpath:"..\..\lib" /nodefaultlib:"libcd" /nologo /subsystem:windows /debug /machine:I386 /pdbtype:sept /out:../../test/tiled.exe]
                prt("LIBS: for [$ccfg] = [$val]\n") if ($dbg_ds13);
                #    "-NEW_OUT-"      => ""
                #    "-NEW_LIBS-"     => "Winmm.lib ws2_32.lib",
                $k2 = '-NEW_LIBS-';
                $rtopt = space_split_to_rh($val);
                if (defined ${$dsp_sub_sub}{$k2}) {
                    $cur = ${$dsp_sub_sub}{$k2};
                    $rcur = space_split_to_rh($cur);
                    add_def_libraries($rcur);
                    $ncur = '';
                    foreach $nitm (keys %{$rtopt}) {
                        next if ($nitm =~ /^\/out:/);
                        next if ($nitm =~ /^\/subsystem:/); # /subsystem:windows
                        next if ($nitm =~ /^\/nologo/); # /nologo
                        next if ($nitm =~ /^\/machine:/); # /machine:I386
                        next if ($nitm =~ /^\/debug/);
                        if ( ! defined ${$rcur}{$nitm}) {
                            $ncur .= ' ' if (length($cur));
                            $ncur .= "$nitm";
                        }
                    }
                    if (length($ncur)) {
                        prt( " Changed LD:$k2: from [$cur], adding [$ncur]") if ($dbg_ds14);
                        $cur .= ' ' if (length($cur));
                        $cur .= $ncur;
                        ${$dsp_sub_sub}{$k2} = $cur;
                        prt( " to [$cur]\n") if ($dbg_ds14);
                    } else {
                        prt( " NO change LD:$k2: from [$cur]\n") if ($dbg_ds14);
                    }

                } else {
                    prtw("WARNING: NOT DEFINED IN:$k2!\n");
                }
                $k2 = '-NEW_OUT-';
                if (defined ${$dsp_sub_sub}{$k2}) {
                    $cur = ${$dsp_sub_sub}{$k2};
                    $ncur = '';
                    foreach $nitm (keys %{$rtopt}) {
                        if ($nitm =~ /^\/out:(.+)$/) {
                            $ncur = "$nitm";
                            last;
                        }
                    }
                    if (length($ncur)) {
                        prt( " Changed OT:$k2: from [$cur], to [$ncur]\n") if ($dbg_ds14);
                        ${$dsp_sub_sub}{$k2} = $ncur;
                    } else {
                        prt( " NO change OT:$k2: from [$cur]\n") if ($dbg_ds14);
                    }
                } else {
                    prtw("WARNING: NOT DEFINED OT:$k2!\n");
                }
            } elsif ($key =~ /^$prp(.+)\s+([\w-]+)$/) {
                $cnam = $1;
                $var  = $2;
                $dbg = 0;
                $dbg = 1 if ($cnam =~ /Debug/i);
                $ccfg = "$cnam|Win32";
                if (! defined $cfg_hash{$ccfg}) {
                    pgm_exit(1,"ERROR: Internal [$ccfg] NOT DEFINED!\n");
                }
                $dsp_sub_sub = $cfg_hash{$ccfg};
                #    "-NEW_OUTD-"     => "\"Release\"",
                #    "-NEW_INTER-"    => "\"Release\"",
                #        ${$rds}{"-NEW_OUTD-"}  = '"Debug"';
                #        ${$rds}{"-NEW_INTER-"} = '"Debug"';
                $k2 = $var;
                if ($var eq '-NEW_OUTD-') {
                    if (defined ${$dsp_sub_sub}{$k2}) {
                        $cur = ${$dsp_sub_sub}{$k2};
                        if ($cur eq $val) {
                            prt( " NO change OD:$k2: from [$cur]\n") if ($dbg_ds14);
                        } else {
                            $ncur = "\"$val\"";
                            prt( " Changed OD:$k2: from [$cur], to [$ncur]\n") if ($dbg_ds14);
                            ${$dsp_sub_sub}{$k2} = $ncur;
                        }
                    } else {
                        prtw("WARNING: NOT DEFINED OD:$k2!\n");
                    }
                } elsif ($var eq '-NEW_INTER-') {
                    if (defined ${$dsp_sub_sub}{$k2}) {
                        $cur = ${$dsp_sub_sub}{$k2};
                        if ($cur eq $val) {
                            prt( " NO change OD:$k2: from [$cur]\n") if ($dbg_ds14);
                        } else {
                            $ncur = "\"$val\"";
                            prt( " Changed OD:$k2: from [$cur], to [$ncur]\n") if ($dbg_ds14);
                            ${$dsp_sub_sub}{$k2} = $ncur;
                        }
                    } else {
                        prtw("WARNING: NOT DEFINED OD:$k2!\n");
                    }
                } else {
                    prtw("WARNING: TO DO OUTS: [$ccfg] [$var] [$val]\n");
                }
            } else {
                # check if MISSED something, or deliberately to ignore
                if ($key =~ /^MTL\s*/) {
                    # ignore MTL = [midl.exe]
                } elsif ($key =~ /^RSC\s*/) {
                    # ignore RSC = [rc.exe]
                } elsif ($key =~ /^PROJECT_NAME\s*/) {
                    # already handled PROJECT_NAME = [tile]
                } elsif ($key =~ /^LINK32\s*/) {
                    # ignore LINK32 = [link.exe]
                } elsif ($key =~ /^PROJECT_TYPE\s*/) {
                    # already done PROJECT_TYPE = [Win32 (x86) Application]
                } elsif ($key =~ /^CPP$/) {
                    # ignore CPP = [cl.exe]
                } elsif ($key =~ /^BSC32\s*/) {
                    # ignore BSC32 = [bscmake.exe]
                } elsif ($key =~ /^CFG$/) {
                    # already handled
                } elsif ($key =~ /^LIB32$/) {
                    # static library creation
                } elsif ($key =~ /^LIB\s+/) {
                    # not sure what this is...
                } else {
                    prtw("WARNING: IGNORING [$key] = [$val] CHECK ME!\n");
                }
            }
        }
        #pgm_exit(1,"TEMP EXIT");
        # $keyin = 'DEFINITIONS'; # Key [DEFINITIONS] Count 12
        # my $rcfgs = ${$rh}{'PROJECT_CFGS'};
        $keyout = 'PROJECT_CFGS';
        #                   Debug      -NEW_OUTD- Debug|WIN32
        # push(@{$rcfgs}, [ $confname, $var1,     $conf,      $dsp_sub_sub ]);
        ${$rh}{$keyout} = [ @cfgs ];

    } else {
        prt("No 'DEFINITIONS' in ref hash!\n") if (VERB9());
    }
    $keyin = 'SOURCES';
    $keyout = 'PROJECT_SRCS';
    $scnt = 0;
    if (defined ${$rdsp}{$keyin}) {
        $rsrcs = ${$rdsp}{$keyin};
        $scnt = scalar @{$rsrcs};
        prt("Transferring $scnt sources to sln hash...\n") if ($scnt || VERB9());
        @src = ();
        for ($i = 0; $i < $scnt; $i++) {
            # FROM
            $src = ${$rsrcs}[$i][0];
            $ff  = ${$rsrcs}[$i][1];
            $grp = ${$rsrcs}[$i][2];
            $flt = ${$rsrcs}[$i][3];
            # TO
            # push(@{$src_ref}, [$src, $fname, $flist, 0, '' ]); # and PUSH onto SOURCE stack
            push(@src,          [$src, $grp,    $flt,   0, '' ]);
        }
        ${$rh}{$keyout} = [ @src ];
        $chkcnt++ if ($scnt);
    }

    if ($chkcnt >= $pass) {
        ${$rok} = 1;
        prt("Setting OK to write DSP...\n");
    } else {
        prt("Transfer FAILED for some reason!\n") if ($scnt);
    }
    return $rh;
}

sub process_one_dsp($) {
    my ($inf) = @_;
    my ($key,$val);
    my $dbg = 0;
    $dbg |= 1 if (VERB1());
    $dbg = -1 if (VERB9());
    my $ok = 0;
    if (open INF1, "<$inf") {
        my @lines = <INF1>;
        close INF1;
        my $lncnt1 = scalar @lines;
        my ($n,$d) = fileparse($inf);
        $d = cwd() if ($d =~ /^\.(\\|\/)$/);
        my $ref_hash = process_DSP3($in_file1,$n,$d,$dbg);
        show_dsp_rh($ref_hash);
        if ($write_dsp_file) {
            my $rh = get_vclike_ref_from_dsp_ref($ref_hash,$inf,\$ok);
            if ($ok) {
                prt("Writting DSP [$tmpout]...\n");
                write_hash_to_DSP3($tmpout,$rh,$dbg_write);
            }
        }
    } else {
        prt("Error: Unable to open [$inf]!\n");
    }
}

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

parse_args(@ARGV);

#set_all_debug(0);

# load FILE 1
process_one_dsp($in_file1);

pgm_exit(0,"");
############################################################


sub parse_args {
    my (@av) = @_;
    my $cnt = 0;
    my $ex = 0;
    while (@av) {
        $cnt++;
        my $arg = $av[0];
        if ($arg =~ /^-/) {
            my $sarg = substr($arg,1);
            $sarg = substr($sarg,1) while ($sarg =~ /^-/);
            if (($sarg =~ /^h/i)||($sarg eq '?')) {
                give_help();
                pgm_exit(0,"HELP exit(0)");
            } elsif ($sarg =~ /^l/) {
                $load_log = 1;
                prt("Set to load log at end.\n") if (VERB1());
            } elsif ($sarg =~ /^c/) {
                $show_configs = 1;
                prt("Set to show configurations list.\n") if (VERB1());
            } elsif ($sarg =~ /^d/) {
                $show_definitions = 1;
                prt("Set to show defintions list.\n") if (VERB1());
            } elsif ($sarg =~ /^s/) {
                $show_source = 1;
                prt("Set to show source list.\n") if (VERB1());
            } elsif ($sarg =~ /^v(.*)$/) {
                $sarg = $1;
                if ((defined $sarg) && ($sarg =~ /^\d+$/)) {
                    $verbose = $sarg;
                } elsif ((defined $sarg) && ($sarg =~ /^v/)) {
                    $verbose++;
                    $sarg = substr($sarg,1);
                    while ($sarg =~ /^v/) {
                        $verbose++;
                        $sarg = substr($sarg,1);
                    }
                } else {
                    $verbose++;
                }
                prt("Bumped verbosity [$verbose].\n") if (VERB1());
            } elsif ($sarg =~ /^w/) {
                $write_dsp_file = 1;
                prt("Set to write DSP file.\n") if (VERB1());
            } else {
                prt("ERROR: Unknown arg [$arg]!\n");
                $ex++;
            }
        } else {
            # bare argument
            if ($cnt == 1) {
                $in_file1 = File::Spec->rel2abs($arg);
                prt("Set input file to [$in_file1]\n") if (VERB1());
            } else {
                prt("ERROR: Already have input file [$in_file1]! What is this [$arg]?\n");
                $ex++;
            }
        }
        shift @av;
    }
    pgm_exit(1,"ERROR: No input file found in command!\n") if (length($in_file1) == 0);
    pgm_exit(1,"ERROR IN COMMAND ARGUMENTS!") if ($ex);
}

sub give_help {
    prt("$pgmname: version $my_version\n");
    prt("Usage: $pgmname [options] input_dsp_file\n");
    prt("Options:\n");
    prt(" --help  (-h or -?) = This help, and exit(0).\n");
    prt(" --configs     (-c) = Show configurations. (or -v2)\n");
    prt(" --definitions (-d) = Show defintions. (or -v2)\n");
    prt(" --load        (-l) = Load LOG file at end.\n");
    prt(" --source      (-s) = Show source list. (or -v2)\n");
    prt(" --verb        (-v) = Bump verbosity. (Def=$verbose)\n");
    prt(" --write       (-w) = Write DSP file [$tmpout], from information.\n");
    prt("To parse the input file as a DSP file, and show its contents.\n");
}

# eof - showdsp.pl
