#!/bin/perl -w
# NAME: movedsp.pl
# AIM: Given a path to a DSP file, move it to a new target directory,
# fixing all the relative paths of the SOURCE files, and maybe attempting
# to 'fix' the CPP lines
# 07/01/2011 - Review of this utility, using later lib utilities
# 05/03/2010 geoff mclane http://geoffair.net/mperl
use strict;
use warnings;
use File::Basename; # split ($name,$dir) = fileparse($ff); or ($nm,$dir,$ext) = fileparse( $fil, qr/\.[^.]*/ );
my $perl_root = 'C:\GTools\perl';
unshift(@INC,$perl_root);
#require 'logfile.pl' or die "Unable to load logfile.pl ...\n";
#require 'fgutils02.pl' or die "Unable to load fgutils02.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' ...\n";
require 'lib_dsphdrs.pl' or die "Unable to load 'lib_dsphdrs.pl' ...\n";
require 'lib_vcscan.pl' or die "Unable to load 'lib_vcscan.pl' ...\n";
# log file stuff
my ($LF);
my $pgmname = $0;
if ($pgmname =~ /\w{1}:\\.*/) {
   my @tmpsp = split(/\\/,$pgmname);
   $pgmname = $tmpsp[-1];
}
my $outfile = $perl_root."\\temp.$pgmname.txt";
open_log($outfile);

my $load_out = 1; # load output at end

my $root_dir = 'C:\FG\28';
my $in_file = $root_dir.'\flightgear\flightgear.dsp';
my $targ_dir = $root_dir.'\fgfs';

#my $in_file = 'C:\FG\27\curl\build\postit2.dsp';
#my $in_file  = 'C:\GTools\tools\Spy5\Spy5.dsp';
#my $targ_dir = 'C:\GTools\tools\Spy5\build';

# DEBUG
my $dbg_01 = 1; # prt("Enter CFG [$cfg]\n") if ($dbg_01);, AND ELSIF, ENDIF
my $dbg_02 = 0; # debug space_split (and EXIT)
my $dbg_03 = 0; # try big list

my @warnings = ();
# forward
sub show_warnings($);

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

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

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

# APP_TYPE - PROJECT_APTP
# $app_console_stg  = 'Console Application'
# $app_windows_stg  = 'Application'
# $app_dynalib_stg  = 'Dynamic-Link Library'
# $app_statlib_stg  = 'Static Library'
# DSP TYPES
# TARGTYPE "Win32 (x86) Application" 0x0101
# TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102
# TARGTYPE "Win32 (x86) Console Application" 0x0103
# TARGTYPE "Win32 (x86) Static Library" 0x0104

# from scanvc.pl library
#sub get_default_ref_hash($) {
#    my ($fil) = @_;
#    my %hash = ();
#    my $rh = \%hash;
#    ${$rh}{'PROJECT_VERS'} = 1; # version of the HASH
#    ${$rh}{'PROJECT_FILE'} = $fil;
#    ${$rh}{'PROJECT_FLAG'} = 0;
#    ${$rh}{'PROJECT_APTP'} = '';
#    ${$rh}{'PROJECT_CCNT'} = 0; # count of configurations
#    ${$rh}{'PROJECT_CFGS'} = [ ];
#    ${$rh}{'PROJECT_SRCS'} = [ ];
#    ${$rh}{'CURR_FLAG'}    = 0;
#    ${$rh}{'CURR_LOFF'}    = 0; # last/current source OFFSET
#    ${$rh}{'CURR_LINE'}    = '<not started>';
#    return $rh;
#}
sub get_def_dsp_hash_ref($) {
    my ($fil) = @_;
    my $rh = get_default_ref_hash($fil);
    #${$rh}{'PROJECT_VERS'} = 1; # version of the HASH
    #${$rh}{'PROJECT_FILE'} = $fil;
    #${$rh}{'PROJECT_FLAG'} = 0;
    #${$rh}{'PROJECT_APTP'} = '';
    ${$rh}{'PROJECT_NAME'} = '';
    #${$rh}{'PROJECT_CCNT'} = 0; # count of configurations
    #${$rh}{'PROJECT_CFGS'} = [ ];
    #${$rh}{'PROJECT_SRCS'} = [ ];
    #${$rh}{'CURR_FLAG'}    = 0;
    #${$rh}{'CURR_LOFF'}    = 0; # last/current source OFFSET
    #${$rh}{'CURR_LINE'}    = '<not started>';
    return $rh;
}

sub get_tool_set_ref() {
   my %tools = (
      'CFG' => '',
      'CPP' => '',
      'RSC' => '',
      'BSC32' => '',
      'LINK32' => '',
      'MTL' => '',
      'LIB32' => '',
      'F90' => ''
   );
   return \%tools;
}

sub set_per_cfg_name($$) {
   my ($rh,$test) = @_;
   my ($tmp);
   ${$rh}{'TEMP_GOT_DSP'} = 0;
   # go for more tests
   my $name = '';
   my $type = '';
   if ( get_project_name($rh, \$name) && (length(trim_all($name)) != 0)) {
       if ( get_project_type($rh, \$type) ) {
           # can get the FETCH FUNCTION
           my ($func);
           if ( get_fetch_function($type,$test,\$func,0) ) {
               ${$rh}{'TEMP_GOT_DSP'} = 1;
               my $stg = $func->();
               ${$rh}{'TEMP_DSP_STG'} = $stg;
               ${$rh}{'TEMP_FECTH_F'} = $func;
               ### prt("Setting 'TEMP_GOT_DSP'\n");
           } else {
               prtw("ERROR: [$test] Unable to get fetch function for type!\n");
           }
       } else {
           prtw("ERROR: Unable to get project type!\n");
       }
   } else {
       prtw("ERROR: Unable to get project name!\n");
   }
}


#  ( $cfgnm, \%cfgnames, $cfgnamcnt );
sub check_cfg_name($$$$) {
    my ($rh,$test,$rcns, $ccnt) = @_;
    my ($tmp);
    my $fnd = 0;
    ${$rh}{'TEMP_GOT_DSP'} = 0;
    ### prt("Killed 'TEMP_GOT_DSP'\n");
    foreach $tmp (keys %{$rcns}) {
        $fnd++;
        if ($tmp eq $test) {
            set_per_cfg_name($rh,$test);
            return $fnd;
        }
   }
   prt("ERROR: CFG Name NOT found [$test]! Have list $ccnt...\n");
   foreach $tmp (keys %{$rcns}) {
      prt("$tmp\n");
   }
   pgm_exit(1,"ERROR: Check and FIX CODE for [$test]\n");
   return 0;
}

# $tmp, \@targtypes, $targtcnt );
sub check_targ_type($$$) {
   my ($test, $ra, $cnt) = @_;
   my ($k);
   for ($k = 0; $k < $cnt; $k++) {
      if (${$ra}[$k] eq $test) {
         return ($k + 1);
      }
   }
   prt( "ERROR: DIFFERENT TARG TYPE! [$test] Have $cnt, as follows...\n" );
   for ($k = 0; $k < $cnt; $k++) {
      prt( "${$ra}[$k]\n");
   }
   pgm_exit(1,"ERROR: DIFFERENT TARG TYPE! [$test] FIX, CHECK CODE\n");
   return 0;
}

# how it is done in scanvc.pl
#     1    2    3    4      5    6         7     8
# my ($xln,$rah,$tag,$pname,$fil,$projname,$line,$flag);
#sub extract_curr_items($$$$$$$$$) {
#            1     2     3     4     5     6     7     8
#    my ($rh,$rxln,$rrah,$rtag,$rpnm,$rfil,$rnam,$rlin,$rflg) = @_;
#    ${$rxln} = ${$rh}{'CURR_LINE'};   # 1
#    ${$rrah} = ${$rh}{'CURR_HASH'};   # 2
#    ${$rtag} = ${$rh}{'CURR_TAG'};    # 3
#    ${$rpnm} = ${$rh}{'CURR_NAME'};   # 4
#    ${$rfil} = ${$rh}{'PROJECT_FILE'};# 5
#    ${$rnam} = ${$rh}{'PROJECT_NAME'};# 6
#    ${$rlin} = ${$rh}{'CURR_TEXT'};   # 7
#    ${$rflg} = ${$rh}{'CURR_FLAG'};   # 8
#}
#sub add_vs_config_item($) {
sub add_dsp_config_item($) {
    my ($rh) = @_;
    my ($xln,$rah,$tag,$pname,$fil,$projname,$line,$flag);
    extract_curr_items($rh,\$xln,\$rah,\$tag,\$pname,\$fil,\$projname,\$line,\$flag);
    my $conf = $pname;              # like ReleaseSSE|WIN32
    my @arr = split(/\|/,$pname);   # split it
    my $confname = $arr[0];         # get just 'ReleaseSSE' 
    ${$rh}{'CURR_CONF'} = $confname;
    ${$rh}{'CURR_CON1'} = $conf;
    my $dnapptype = ${$rh}{'PROJECT_APTP'};
    # 28/09/2008 - note, has quotes added
    # "-NEW_OUTD-" $out_dir
    # "-NEW_INTER-" $int_dir
    my $var1 = "-NEW_OUTD-";
    my $var2 = "-NEW_INTER-";
    my ($dsp_sub_sub, $seek, $adddeps, $apptype);
    if ($conf =~ /Debug/i) {
        $dsp_sub_sub = get_default_sub3(1);
    } else {
        $dsp_sub_sub = get_default_sub3(0);
        if (!($conf =~ /Release/i)) {
            prtw( "WARNING:$xln pname=[$conf] NOT Debug or Release - def to REL! [$fil]\n" );
        }
    }
    my $rcfgs = get_project_configs($rh);   # 'PROJECT_CFGS'
    my $cnt = scalar @{$rcfgs};
    if ($cnt) {
        # check is NOT a duplicate of an existing item
        prt("Adding config [$confname] [$conf] to count of $cnt\n");
    } else {
        prt("Adding config [$confname] [$conf] as FIRST\n");
    }
    push(@{$rcfgs}, [ $confname, $var1, $conf, $dsp_sub_sub ]);
}

sub space_split_with_quotes2 {
    my ($txt) = shift;
    my @a = ();
    my $ll = length($txt);
    my ($j, $c, $wd, $inq, $pc);
    $wd = '';
    $inq = 0;
    $c = '';
    for ($j = 0; $j < $ll; $j++) {
        $pc = $c;
        $c = substr($txt,$j,1); #// char by char
        if ($inq) {
            $inq = 0 if ($c eq '"');
        } elsif ($c eq '"') {
            $inq = 1;
        }
        if ($c =~ /\s/) {    # if a SPACEY char
            if ($inq) {
                $wd .= $c;    # keep spaces, if IN double quotes
            } else {
                push(@a,$wd) if length($wd);    # stack word, if any
                $wd = '';    # and clear word
            }
        } else {
            $wd .= $c;    # store it
        }
    }
    push(@a,$wd) if length($wd);    # stack word, if any
    return @a;
}

# compiler flags
my %compile_flags = (
    'nologo' => 0,
    'W3'     => 0,
    'Gm'     => 0,
    'GR'     => 0,
    'GX'     => 0,
    'Od'     => 0,
    'MT'     => 0,
    'MTd'    => 0,
    'MD'     => 0,
    'MDd'    => 0,
    'I'      => 1,
    'D'      => 1,
    'FD'     => 0,
    'GZ'     => 0,
    'c'      => 0,
    'O2'     => 0,
    'YX'     => 0,
    'ZI'     => 0,
    'Zi'     => 0,
    );

sub get_library_stg_hash($$) {
    my ($cfg,$ra) = @_;
    my @arr = space_split_with_quotes2($cfg);
    my $cnt = scalar @arr;
    my ($i,$itm);
    my %h = ();
    # prt("Doing switch hash for [$cfg]\n" );
    for ($i = 0; $i < $cnt; $i++) {
        $itm = $arr[$i];
        $h{$itm} = 1;
    }
    ${$ra} = \@arr;
    return \%h;
}

# /libpath:"abc" /out:"abc"
sub get_library_stg_hash2($) {
    my ($cfg) = @_;
    my @arr = space_split_with_quotes2($cfg);
    my $cnt = scalar @arr;
    my ($i,$itm,$ord,$key,$val);
    my %h = ();
    # prt("Doing switch hash for [$cfg]\n" );
    $ord = 0;
    for ($i = 0; $i < $cnt; $i++) {
        $itm = $arr[$i];
        $ord++;
        if ($itm =~ /^\/libpath:(.+)$/) {
            $val = $1;
            $key = sprintf("%04d_libpath",$ord);
        } elsif ($itm =~ /^\/out:(.+)$/) {
            $val = $1;
            $key = sprintf("%04d_out",$ord);
        } elsif ($itm =~ /^\w/) {
            $key = sprintf("%04d_$itm",$ord);
            $val = 1;
        }
        $h{$itm} = 1;
    }
    return \%h;
}


sub get_config_stg_hash($) {
    my ($cfg) = @_;
    my @arr = space_split_with_quotes2($cfg);
    my $cnt = scalar @arr;
    my ($i,$itm,$it2,$val,$tmp,$key,$ord);
    my %h1 = ();
    $ord = 0;
    # prt("Doing switch hash for [$cfg]\n" );
    for ($i = 0; $i < $cnt; $i++) {
        $itm = $arr[$i];
        if ($itm =~ /^[\/-]{1}/) {
            $it2 = substr($itm,1);
            $ord++;
            $key = sprintf("%04d_$it2",$ord);
            if (defined $compile_flags{$it2}) {
                if ($compile_flags{$it2}) {  # need NEXT param
                    $i++; # take next
                    if (defined $h1{$key}) {
                        $val = $h1{$key};
                        push(@{$val}, $arr[$i]);
                        $h1{$key} = $val;
                    } else {
                        my @a = ();
                        push(@a, $arr[$i]);
                        $h1{$key} = [@a];
                    }
                } else {
                    if (defined $h1{$key}) {
                        prt( "Repeated switch [$it2]\n" );
                        $h1{$key}++;
                    } else {
                        $h1{$key} = 1;
                    }
                }
            } elsif ($it2 =~ /^Yu"(\w|\.|-)+"/) {
                $tmp = $1;
                $it2 = 'Yu';
                $key = sprintf("%04d_$it2",$ord);
                # we have a like [Yu"stdafx.h"]
                if (defined $h1{$key}) {
                     prt( "Repeated switch [$it2] got [".$h1{$key}."], and now [$tmp]\n" );
                } else {
                    $h1{$key} = $tmp;
                }
            } elsif ($it2 =~ /^NEW_(\w+)/) {
                # skip the special substitute items '-NEW_BBB-'
            } else {
                prt("1:WHAT is THIS switch [$it2]? full [$itm]!!!\n");
            }
         } else {
            prt("1:WHAT is THIS [$itm] non switch?\n");
         }
    }
    return \%h1;
}

sub get_cpp_line($) {
    my ($stg) = @_;
    my @arr = split("\n",$stg);
    my ($line);
    foreach $line (@arr) {
        # # ADD CPP /nologo /W3 /GR /GX /O2 -NEW_RT- -NEW_INCS- /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" -NEW_DEFS- /FD /c
        if ($line =~ /^\#\s+ADD\s+CPP\s+(.+)$/) {
            return $1;
        }
    }
    return '';
}

sub get_link_line($) {
    my ($stg) = @_;
    my @arr = split("\n",$stg);
    my ($line);
    foreach $line (@arr) {
        # # 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 odbc32.lib odbccp32.lib comctl32.lib Msimg32.lib Winmm.lib wsock32.lib SimGear.lib sg_d.lib pui_d.lib puAux_d.lib fnt_d.lib net_d.lib ul_d.lib js_d.lib zlibd.lib osgd.lib osgDBd.lib osgTextD.lib osgUtild.lib OpenThreadsd.lib OpenAL32.lib alut.lib pthreadVC2_d.lib osgViewerd.lib osgGAd.lib osgParticled.lib /libpath:"..\SimGear\Debug" /libpath:"..\PLIB" /libpath:"..\zlib-1.2.3\projects\visualc6\Win32_LIB_Debug" /libpath:"..\OpenSceneGraph\lib" /libpath:"..\OpenThreads\lib\Win32" /libpath:"C:\Program Files\OpenAL 1.1 SDK\libs\Win32" /libpath:"..\alut\admin\VisualStudioDotNET\alut\Debug" /libpath:"..\freeglut\$(IntDir)Static" /libpath:"..\pthreads" /libpath:"..\3rdparty\lib" /nologo /subsystem:console /debug /machine:I386 /out:..\bin\FlightGearD.exe
        if ($line =~ /^\#\s+ADD\s+LINK32\s+(.+)$/) {
            return $1;
        }
    }
    return '';
}


# eliminate any 'old' from the 'new', and return any new remainder if any
sub return_remainder_stg($$) {
    my ($old, $new) = @_;
    my $rch2 = get_config_stg_hash($old);
    my $rch1 = get_config_stg_hash($new);
    my $defs = '';

    my ($key,$val,$opt,$dsp);
    my ($key2,$val2,$opt2,$v,$v2);
    my $cnt = 0;
    my $dcnt = 0;
    # for each NEW key
    foreach $key (sort keys %{$rch1}) {
        $val = ${$rch1}{$key};
        $opt = $key;
        $opt =~ s/^\d+_//;
        $dsp = 1;
        if (ref($val) eq 'ARRAY') {
            my %dupes = ();
            foreach $v (@{$val}) {
                if (! defined $dupes{$v}) {
                    # search same in OLD
                    foreach $key2 (keys %{$rch2}) {
                        $val2 = ${$rch2}{$key2};
                        $opt2 = $key2;
                        $opt2 =~ s/^\d+_//;
                        if (ref($val2) eq 'ARRAY') {
                            foreach $v2 (@{$val2}) {
                                if ($v eq $v2) {
                                    $dsp = 0; # FOUND SAME
                                    last;
                                }
                            }                        
                        }
                    }
                    if ($dsp) {
                        $defs .= ' ' if (length($defs));
                        $defs .= "/$opt $v";
                        $dcnt++;
                    }
                    $dupes{$v} = 1;
                }
            }
        } else {
            # search the OLD
            foreach $key2 (keys %{$rch2}) {
                $val2 = ${$rch2}{$key2};
                $opt2 = $key2;
                $opt2 =~ s/^\d+_//;
                if (ref($val2) eq 'ARRAY') {
                    # need only single items here
                } else {
                    if ($opt eq $opt2) {
                        $dsp = 0; # FOUND SAME
                        last;
                    }
                }
            }
            if ($dsp) {
                $defs .= ' ' if (length($defs));
                $defs .= "/$opt";
                $dcnt++;
            }
        }
        $cnt++;
    }
    return $defs;
}

sub no_case_file_defined($$) {
    my ($fil,$rh) = @_;
    my $lcf = lc($fil);
    my ($key);
    return 1 if ( defined ${$rh}{$fil} );
    foreach $key (keys %{$rh}) {
        if (lc($key) eq $lcf) {
            return 1;
        }
    }
    return 0;
}

sub return_lib_remain_stg($$) {
    my ($def,$usr) = @_;
    my ($rordarr1,$rordarr2);
    my $rch1 = get_library_stg_hash($usr,\$rordarr1); # users suggestion
    my $rch2 = get_library_stg_hash($def,\$rordarr2); # current list
    my $adds = '';
    my ($key,$dsp);
    my ($path,$key2,$path2);
    my %dupe = ();
    $dsp = 0;
    foreach $key (@{$rordarr1}) {
        next if (defined $dupe{$key});
        $dupe{$key} = 1;
        $dsp = 1;
        if ($key =~ /^\/libpath:(.+)$/) {
            $path = $1;
            # compare with all other library paths in present
            if ( defined ${$rch2}{$key}) {
                $dsp = 0;
            } else {
                foreach $key2 (keys %{$rch2}) {
                    if ($key2 =~ /^\/libpath:(.+)$/) {
                        $path2 = $1;
                        if (lc($path) eq lc($path2)) {
                            $dsp = 0; # already have this 'libpath'
                            last;
                        }
                    }
                }
            }
            #$rctxt = \$libpaths;
        } elsif ($key =~ /^\/out:(.+)$/) {
            # on the very ODD chance
            #$out = $1;
            if ( defined ${$rch2}{$key}) {
                $dsp = 0;
            } else {
                # set -NEW-OUT- to this
            }
            #$rctxt = \$output;
        } elsif ($key =~ /^\w/) {
            if ( no_case_file_defined($key,$rch2) ) {
                # already got this library
                $dsp = 0;
            }
            # $rctxt = \$newlibs;
        } else {
            # things like /nologo /subsystem:console /machine:I386
            if ( defined ${$rch2}{$key}) {
                $dsp = 0;
            }
            # $rctxt = \$others;
        }
        if ($dsp) {
            $adds .= ' ' if (length($adds));
            $adds .= $key;
            # ${$rctxt} .= ' ' if (length(${$rctxt}));
            # ${$rctxt} .= $key;
        }
    }
    return $adds;
}

# -NEW_LIBS- and -NEW_OUT-
sub process_library_stg2($$$) {
    my ($rh,$cfg,$add) = @_;
    my $got_dsp = 0;
    my $got_sub_sub = 0;
    my ($rsubsub,$rordarr1,$rordarr2,$rsa);
    my ($path,$out);
    if ( (defined ${$rh}{'TEMP_GOT_DSP'}) && (defined ${$rh}{'TEMP_DSP_STG'}) ) {
        $got_dsp = ${$rh}{'TEMP_GOT_DSP'};
    }
    if (defined ${$rh}{'TEMP_DSP_SUB'} ) {
        $rsubsub = ${$rh}{'TEMP_DSP_SUB'}; # = $dsp_sub_sub; # direct access to substitution block -NEW_???- items
        $got_sub_sub = 1;
    }
    my $clibs = '';
    my $libpaths = '';
    my $output = '';
    my $newlibs = '';
    my $others = '';
    my $libtxt = '';
    my $rctxt = \$others;
    my ($val,$nval);

    if ($got_sub_sub && $got_dsp) {
        $clibs = get_link_line(${$rh}{'TEMP_DSP_STG'});
        $rsa  = get_list_of_subs($clibs);  # collect list of '-NEW_...' tags
        my $rch1 = get_library_stg_hash($cfg,\$rordarr1); # users suggestion
        my $rch2 = get_library_stg_hash($clibs,\$rordarr2); # current list
        prt("CHG [$clibs]\n to [$cfg]\n");
        my $adds = '';
        my ($key,$dsp);
        my %dupe = ();
        $dsp = 0;
        #foreach $key (keys %{$rch1}) {
        foreach $key (@{$rordarr1}) {
            next if (defined $dupe{$key});
            $dupe{$key} = 1;
            $dsp = 1;
            $rctxt = \$others;
            if ($key =~ /^\/libpath:(.+)$/) {
                $path = $1;
                # compare with all other library paths in present
                if ( defined ${$rch2}{$key}) {
                    $dsp = 0;
                }
                $rctxt = \$libpaths;
            } elsif ($key =~ /^\/out:(.+)$/) {
                # on the very ODD chance
                $out = $1;
                if ( defined ${$rch2}{$key}) {
                    $dsp = 0;
                } else {
                    # set -NEW-OUT-
                }
                $rctxt = \$output;
            } elsif ($key =~ /^\w/) {
                if ( no_case_file_defined($key,$rch2) ) {
                    # already got this library
                    $dsp = 0;
                }
                $rctxt = \$newlibs;
            } else {
                # things like /nologo /subsystem:console /machine:I386
                if ( defined ${$rch2}{$key}) {
                    $dsp = 0;
                }
                $rctxt = \$others;
            }
            if ($dsp) {
                $adds .= ' ' if (length($adds));
                $adds .= $key;
                ${$rctxt} .= ' ' if (length(${$rctxt}));
                ${$rctxt} .= $key;
            }
        }
        prt("ADD [$adds]\n");
        prt("newlibs: $newlibs\n") if (length($newlibs));
        prt("libpath: $libpaths\n") if (length($libpaths));
        prt("output:  $output\n") if (length($output));
        prt("Others:  $others\n") if (length($others));
        $dsp = scalar @{$rsa};
        prt("Got $dsp KEYS: ");
        foreach $key (@{$rsa}) {
            prt("$key ");
        }
        prt("\n");
        foreach $key (@{$rsa}) {
            if ($key eq '-NEW_LIBS-') {
                $libtxt = $newlibs;
                $libtxt .= ' ' if (length($libtxt) && length($libpaths));
                $libtxt .= $libpaths;
                $rctxt = \$libtxt;
            } elsif ($key eq '-NEW_OUT-') {
                $rctxt = \$output;
            } else {
                pgm_exit(1,"ERROR Un-cased value! [$key] - FIX ME!!!\n");
            }
            if (defined ${$rsubsub}{$key}) {
                $val = ${$rsubsub}{$key};
                $nval = ${$rctxt};
                if (length($val)) {
                    if (length($nval)) {
                        if ($key eq '-NEW_OUT-') {
                            prt("$key = CHG [$nval] to [$val]\n");
                            ${$rsubsub}{$key} = $nval;
                        } else {
                            prt("$key = MRG [$val] and [$nval]\n");
                            $nval = return_lib_remain_stg($val,$nval);
                            if (length($nval)) {
                                prt("$key = ADD [$nval]\n");
                                ${$rsubsub}{$key} .= " $nval";
                            }
                        }
                    }
                } else {
                    # no current value, so just SET the new value
                    if (length($nval)) {
                        prt("$key = SET to [$nval]\n");
                        ${$rsubsub}{$key} = $nval;
                    }
                }
            }
        }

    } else {
        prtw("WARNING: Discarding [$cfg]\n");
    }
}


sub process_config_stg2($$$) {
    my ($rh,$cfg,$add) = @_;
    my $rch = get_config_stg_hash($cfg);
    my ($key,$val,$cnt,$v,$opt,$cdefs,$rch2,$dsp);
    my ($key2,$val2,$v2,$opt2,$dcnt,$defs,$rsubsub,$rsa);
    my $got_dsp = 0;
    my $got_sub_sub = 0;
    if ( (defined ${$rh}{'TEMP_GOT_DSP'}) && (defined ${$rh}{'TEMP_DSP_STG'}) ) {
        $got_dsp = ${$rh}{'TEMP_GOT_DSP'};
    }
    $cdefs = '';

    if ($got_dsp) {
        $cdefs = get_cpp_line(${$rh}{'TEMP_DSP_STG'});
        prt("Def defs: $cdefs\n");
        $rsa  = get_list_of_subs($cdefs);  # collect list of '-NEW_...' tags
        $rch2 = get_config_stg_hash($cdefs);
        if (defined ${$rh}{'TEMP_DSP_SUB'} ) {
            $rsubsub = ${$rh}{'TEMP_DSP_SUB'}; # = $dsp_sub_sub; # direct access to substitution block -NEW_???- items
            $got_sub_sub = 1;
        }
    } else {
        prt("No fetch of default type DSP definitions...\n");
    }
    $cnt = 0;
    $dcnt = 0;
    $defs = '';
    # collect any remainder in groups
    my $runtime = '';
    my $includes = '';
    my $defines = '';
    my $others = '';
    my $rcgrp = \$runtime;
    foreach $key (sort keys %{$rch}) {
        $val = ${$rch}{$key};
        $opt = $key;
        $opt =~ s/^\d+_//;
        $dsp = 1;
        if (ref($val) eq 'ARRAY') {
            my %dupes = ();
            foreach $v (@{$val}) {
                if (! defined $dupes{$v}) {
                    if ($got_dsp) {
                        foreach $key2 (keys %{$rch2}) {
                            $val2 = ${$rch2}{$key2};
                            $opt2 = $key2;
                            $opt2 =~ s/^\d+_//;
                            if (ref($val2) eq 'ARRAY') {
                                foreach $v2 (@{$val2}) {
                                    if ($v eq $v2) {
                                        $dsp = 0;
                                        last;
                                    }
                                }                        
                            }
                        }
                    }
                    if ($dsp) {
                        prt("/$opt $v ");
                        $defs .= ' ' if (length($defs));
                        $defs .= "/$opt $v";
                        if ($opt =~ /^D/) {
                            $rcgrp = \$defines;
                        } elsif ($opt =~ /^I/) {
                            $rcgrp = \$includes;
                        } elsif ($opt =~ /^M/) {
                            $rcgrp = \$runtime;
                        } else {
                            $rcgrp = \$others;
                        }
                        $dcnt++;
                        ${$rcgrp} .= ' ' if (length(${$rcgrp}));
                        ${$rcgrp} .= "/$opt $v";
                    }
                    $dupes{$v} = 1;
                }
            }
        } else {
            if ($got_dsp) {
                foreach $key2 (keys %{$rch2}) {
                    $val2 = ${$rch2}{$key2};
                    $opt2 = $key2;
                    $opt2 =~ s/^\d+_//;
                    if (ref($val2) eq 'ARRAY') {
                        # need only single items here
                    } else {
                        if ($opt eq $opt2) {
                            $dsp = 0;
                            last;
                        }
                    }
                }
            }
            if ($dsp) {
                prt("/$opt ");
                $defs .= ' ' if (length($defs));
                $defs .= "/$opt";
                if ($opt =~ /^D/) {
                    $rcgrp = \$defines;
                } elsif ($opt =~ /^I/) {
                    $rcgrp = \$includes;
                } elsif ($opt =~ /^M/) {
                    $rcgrp = \$runtime;
                } else {
                    $rcgrp = \$others;
                }
                ${$rcgrp} .= ' ' if (length(${$rcgrp}));
                ${$rcgrp} .= "/$opt";
                $dcnt++;
            }
        }
        $cnt++;
    }
    prt("\n") if ($dcnt);
    #if ($dcnt < $cnt) {
    if ($cnt) {
        prt("Of $cnt defines, eliminated ".($cnt - $dcnt).", remains [$defs]\n");
        prt("Runtime: $runtime\n") if (length($runtime));
        prt("Defines: $defines\n") if (length($defines));
        prt("Includes: $includes\n") if (length($includes));
        prt("Others: $others\n") if (length($others));
        if ($got_sub_sub) {
            # Others: /YX
            # -NEW_DEFS- = [/D "_CRT_SECURE_NO_WARNINGS"]
            # -NEW_INCS- = []
            # -NEW_RT- = [/MT]
            my $nval = scalar @{$rsa};
            prt("Process $nval keys: ");
            foreach $key (@{$rsa}) { prt("$key "); }
            prt("\n");
            foreach $key (@{$rsa}) {
                if ($key eq '-NEW_DEFS-') {
                    $rcgrp = \$defines;
                } elsif ($key eq '-NEW_INCS-') {
                    $rcgrp = \$includes;
                } elsif ($key eq '-NEW_RT-') {
                    $rcgrp = \$runtime;
                } else {
                    $rcgrp = \$others;
                    next;
                }
                $nval = ${$rcgrp}; # and load the NEW value
                if (defined ${$rsubsub}{$key}) {
                    $val = ${$rsubsub}{$key}; # get the current sub value
                    if (length($val)) {
                        if (length($nval)) {
                            if ($key eq '-NEW_RT-') {
                                prt("$key = CHG [$nval] to [$val]\n");
                                ${$rsubsub}{$key} = $nval;
                            } else {
                                prt("$key = MRG [$val] and [$nval]\n");
                                $nval = return_remainder_stg($val,$nval);
                                if (length($nval)) {
                                    prt("$key = ADD [$nval]\n");
                                    ${$rsubsub}{$key} .= " $nval";
                                }
                            }
                        }
                    } else {
                        # no current value, so just SET the new value
                        if (length($nval)) {
                            prt("$key = SET to [$nval]\n");
                            ${$rsubsub}{$key} = $nval;
                        }
                    }
                } else {
                    prtw("WARNING: key [$key] NOT FOUND! Discarding [$nval]\n");
                }
            } # for each key in the 'substitution' set
        } else {
            prtw("WARNING: Unable to fix the sub sub hash!\nDiscarding: [$defs]\n");
        }
    }
}

sub process_config_stg($$) {
    my ($rh,$cfg) = @_;
    my $rch = get_config_stg_hash($cfg);
    my ($key,$val,$cnt,$v,$opt,$cdefs,$rch2,$dsp);
    my ($key2,$val2,$v2,$opt2,$dcnt,$defs);
    my $got_dsp = 0;
    if ( (defined ${$rh}{'TEMP_GOT_DSP'}) && (defined ${$rh}{'TEMP_DSP_STG'}) ) {
        $got_dsp = ${$rh}{'TEMP_GOT_DSP'};
    }
    $cdefs = '';
    if ($got_dsp) {
        $cdefs = get_cpp_line(${$rh}{'TEMP_DSP_STG'});
        prt("Def defs: $cdefs\n");
        $rch2 = get_config_stg_hash($cdefs);
    } else {
        prt("No fetch of default type DSP definitions...\n");
    }
    $cnt = 0;
    $dcnt = 0;
    $defs = '';
    foreach $key (sort keys %{$rch}) {
        $val = ${$rch}{$key};
        $opt = $key;
        $opt =~ s/^\d+_//;
        $dsp = 1;
        if (ref($val) eq 'ARRAY') {
            my %dupes = ();
            foreach $v (@{$val}) {
                if (! defined $dupes{$v}) {
                    if ($got_dsp) {
                        foreach $key2 (keys %{$rch2}) {
                            $val2 = ${$rch2}{$key2};
                            $opt2 = $key2;
                            $opt2 =~ s/^\d+_//;
                            if (ref($val2) eq 'ARRAY') {
                                foreach $v2 (@{$val2}) {
                                    if ($v eq $v2) {
                                        $dsp = 0;
                                        last;
                                    }
                                }                        
                            }
                        }
                    }
                    if ($dsp) {
                        prt("/$opt $v ");
                        $defs .= ' ' if (length($defs));
                        $defs .= "/$opt $v";
                        $dcnt++;
                    }
                    $dupes{$v} = 1;
                }
            }
        } else {
            if ($got_dsp) {
                foreach $key2 (keys %{$rch2}) {
                    $val2 = ${$rch2}{$key2};
                    $opt2 = $key2;
                    $opt2 =~ s/^\d+_//;
                    if (ref($val2) eq 'ARRAY') {
                        # need only single items here
                    } else {
                        if ($opt eq $opt2) {
                            $dsp = 0;
                            last;
                        }
                    }
                }
            }
            if ($dsp) {
                prt("/$opt ");
                $defs .= ' ' if (length($defs));
                $defs .= "/$opt";
                $dcnt++;
            }
        }
        $cnt++;
    }
    prt("\n") if ($dcnt);
    #if ($dcnt < $cnt) {
    if ($cnt) {
        prt("Of $cnt defines, eliminated ".($cnt - $dcnt).", remains [$defs]\n");
    }
}

sub show_name_and_type($) {
    my ($rh) = @_;
    my $name = '';
    my $type = '';
    if ( !get_project_name($rh, \$name) || (length(trim_all($name)) == 0)) {
        prtw("ERROR: Unable to get project name!\n");
        return 0;
    }
    if ( !get_project_type($rh, \$type) ) {
        prtw("ERROR: Unable to get project type!\n");
        return 0;
    }
    if (! defined ${$rh}{'PROJECT_SRCS'} ) {
        prtw("WARNING: Project [$name], type [$type] hash has no SOURCES\n");
        return 0;
    }

    my $rsrcs = ${$rh}{'PROJECT_SRCS'}; # = [ @dsp_sources ];
    my $scnt = scalar @{$rsrcs};
    prt("Project [$name], type [$type], with $scnt sources...\n");
    return $scnt;   # reutrn number of sources
}

# # Microsoft Developer Studio Project File - Name="FlightGear" - Package Owner=<4>
# # Microsoft Developer Studio Generated Build File, Format Version 6.00
# # ** DO NOT EDIT **
# # TARGTYPE "Win32 (x86) Console Application" 0x0103
# CFG=FlightGear - Win32 Debug
# !MESSAGE This is not a valid makefile. To build this project using NMAKE,

# # Begin Project
# PROP AllowPerConfigDependencies 0

# !IF "$(CFG)" == "someconfig"
# # PROP Target_Dir "."
# # ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /YX /c
# ...
# !ELSIF "$(CFG)" == "someconfig"
# ...
# !ENDIF

# # Begin Target
# # Name "FlightGear - Win32 Release"
# # Name "FlightGear - Win32 Debug"
# # Begin Group "Lib_Aircraft"
# # PROP Default_Filter ""
# # Begin Source File
# # End Target
# # End Project
sub set_default_group_and_filter($$$) {
    my ($fil,$rgroup,$rfilter) = @_;
    my $group = '';  # ${$rgroup};
    my $filter = ''; # ${$rfilter};
    my $ret = 0;
    if (is_c_source_extended($fil)) {
        $group = get_def_src_grp();
        $filter = get_def_src_filt();
    } elsif (is_text_ext_file($fil)) {
        # leave unchanged
        # can be blanks, to put this source by its self
    } elsif (is_h_source($fil)) {
        $group = get_def_hdr_grp();
        $filter = get_def_hdr_filt();
    } elsif (is_resource_file($fil)) {
        $group = get_def_rcs_grp();
        $filter = get_def_rcs_filt();
    } elsif (is_h_source_extended($fil)) {
        $group = get_def_hdr_grp();
        $filter = get_def_hdr_filt();
    #} else {
    #    $group = get_def_spl_grp();
    #    $filter = get_def_spl_filt();
    }

    if ((length($group) > 0) && (length(${$rgroup}) == 0)) {
        ${$rgroup} = $group;
        $ret |= 1;
    }
    if ((length($filter) > 0) && (length(${$rfilter}) == 0)) {
        ${$rfilter} = $filter;
        $ret |= 2;
    }
    return $ret;
}


sub set_group_and_filter($$$) {
    my ($src, $rgroup, $rfilter) = @_;
    my $group = ${$rgroup};
    my $filter = ${$rfilter};
    return 0 if (length($group) && length($filter));
    if ( set_default_group_and_filter($src,\$group,\$filter) ) {
        prtw("WARNING: Set default filter of group [$group], src [$src], filter [$filter]\n");
        ${$rgroup}  = $group;
        ${$rfilter} = $filter;
        return 1;
    }
    return 0;
}

sub scan_dsp_file_lines($$) {
    my ($file,$rlines) = @_;
    my $lncnt = scalar @{$rlines};
    prt("Processing $lncnt lines from [$file] file...\n");
    my $got_project = 0;
    my $in_project = 0;
    my $in_target = 0;
    my $in_group = 0;
    my ($oline,$line);
    my $projname = '';
    my $rh = get_def_dsp_hash_ref($file);
    my ($i,$lnn,$k,$tmp,$tmp2,$var1,$targnum,$version,@arr,$rcfgs);
    my ($key,$var);
    my @targtypes = ();   # set target type string - san double quotes
    my $targtcnt = 0;
    my $targtype1 = '';
    my $curr_cfg = '';
    my $do_config = 0;
    my $cfg_msg = '';
    my $isdebug = 0;
    my %cfgnames = ();
    my $cfgnamcnt = 0;
    my $cfgnmcnt = 0; # from lines '# Name blah blah blah'
    my ($cfg_proj,$cfg_plat,$cfg_type,$cfg_name,$dsp_sub_sub,$prop);
    my ($base,$flist,$tdir,$igexlib,$intdir,$outdir,$exfrmbld,$add);
    my $bgnsrc = 0;
    my $custom = '';
    my $customstg = '';
    my $special = 0;
    my $specstg = '';
    my $group = '';
    my $have_prop = 0;
    my @dsp_sources = ();
    # process line by line
    for ($i = 0; $i < $lncnt; $i++) {
        $oline = ${$rlines}[$i];
        $oline = substr($oline,0,length($oline)-1) while ($oline =~ /\s$/);
        next if (length($oline) == 0);
        $line = $oline;
        if ($got_project) {
            # had main project line
            if ($line =~ /^!IF\s+"\$\(CFG\)"\s+==\s+"(.+)"\s*$/) {
                $tmp = $1;
                prtw("WARNING: Discarded CONFIG [$curr_cfg]!\n") if (length($curr_cfg));       
                $curr_cfg = $tmp;
                $cfg_msg = 'Enter CFG';
                $do_config = 1;
            } elsif ($line =~ /^!ELSEIF\s+"\$\(CFG\)"\s+==\s+"(.+)"\s*$/) {
                $tmp = $1;
                prtw("WARNING: Got ELSEIF before IF [$curr_cfg]!\n") if (length($curr_cfg) == 0);
                $curr_cfg = $tmp;
                $cfg_msg = 'ElseIf CFG';
                $do_config = 1;
                next;
            } elsif ($line =~ /^!ENDIF\s*$/) {
                $curr_cfg = '';
                next;
            }
            if ($do_config) {
                # "Spy5 - Win32 Debug" or
                # "minigzip - Win32 DLL ASM Release"
                if ($curr_cfg =~ /Debug/i) {
                    $tmp2 = "Debug";
                    $isdebug = 1;
                    $dsp_sub_sub = get_default_sub3(1);
                } elsif ($curr_cfg =~ /Release/i) {
                    $tmp2 = "Release";
                    $isdebug = 0;
                    $dsp_sub_sub = get_default_sub3(0);
                } elsif ($curr_cfg =~ /DLL/) {  # exception for DLL
                    $tmp2 = "ReleaseDLL";
                    $isdebug = 0;
                    $dsp_sub_sub = get_default_sub3(0);
                } else {
                    pgm_exit(1,"ERROR: Did NOT find 'Debug' or 'Release' in [$curr_cfg]!\n");
                }
                @arr = split(/\s/,$curr_cfg);
                $tmp = scalar @arr;
                if ($tmp < 4) {
                     pgm_exit(1,"ERROR: UNmanaged split of [$curr_cfg]. Expected min 4, got $tmp! FIX CODE!\n");
                }
                $cfg_proj = $arr[0];
                $cfg_plat = $arr[2]; # Platform
                $cfg_type = $arr[3]; # Release, Debug, etc 'DLL Universal Unicode Release', or ...
                $cfg_name = $cfg_type;
                # from : C:\FG\27\wxWidgets-2.8.10\build\msw\wx_adv.dsp
                # adv - Win32 DLL Universal Unicode Release
                if ($tmp > 4) {
                    $cfg_type = '';
                    for ($k = 3; $k < $tmp; $k++) {
                        if (($arr[$k] =~ /Release/i)||($arr[$k] =~ /Debug/i)) {
                           $cfg_type = $arr[$k];
                           $arr[$k] = '';
                        }
                    }
                    $cfg_type = 'Release' if (length($cfg_type)==0);
                    $cfg_name = $cfg_type;
                    for ($k = 3; $k < $tmp; $k++) {
                        $cfg_type .= $arr[$k];
                    }
                }
                ${$rh}{'TEMP_DSP_SUB'} = $dsp_sub_sub; # direct access to substitution block -NEW_???- items
                if ($in_target) {
                    # change of CFG item for a specific source - NOT HANDLED
                    ${$rh}{'TEMP_LAST_CFG'} = [ $cfg_name, $var1, $tmp2, $dsp_sub_sub ];
                    ${$rh}{'TEMP_GOT_LAST'} = 1;
                } else {
                    #prt("[dbg_01] Enter CFG [$curr_cfg] [$cfg_name]\n") if ($dbg_01);
                    prt("[dbg_01] $cfg_msg [$curr_cfg] [$cfg_name]\n") if ($dbg_01);
                    ### check_cfg_name($rh, $curr_cfg, \%cfgnames, $cfgnamcnt );
                    set_per_cfg_name( $rh, $curr_cfg );
                    $var1 = "-NEW_OUTD-";
                    $tmp2 = "$cfg_type|$cfg_plat";
                    $rcfgs = ${$rh}{'PROJECT_CFGS'};
                    #                   0       1      2      3
                    # push(@{$rcfgs}, [ $pname, $var1, $conf, $dsp_sub_sub ]);
                    push(@{$rcfgs}, [ $cfg_name, $var1, $tmp2, $dsp_sub_sub ]);
                    ${$rh}{'TEMP_LAST_CFG'} = ${$rcfgs}[-1];
                    ${$rh}{'TEMP_GOT_LAST'} = 1;
                }
                $do_config = 0;
                next;
            }
            $line =~ s/^\#\s+//;
            if ($in_project) {
                if ($line =~ /^End\s+Project\s*$/) {
                    $in_project = 0;
                } elsif ($in_target) {
                    if ($line =~ /^End\s+Target\s*$/) {
                        $in_target = 0;
                    } else {
                        # handle ALL lines until 'End Target'
                        # Name - "FlightGear - Win32 Release"
                        # Name - "FlightGear - Win32 Debug"
                        # Begin Group "Source Files"
                        # PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"
                        # etc
                        # if ($line =^ /^Name\s+-\s+(.+)\s*$/)
                        if ($line =~ /^Name\s+(.+)\s*$/) {
                            $tmp = strip_quotes($1);
                            # # Name - "FlightGear - Win32 Release"
                            # # Name "minigzip - Win32 DLL Release"
                            $tmp =~ s/^-\s+//; # dump any '- ' lead
                            $tmp = strip_quotes($tmp);
                            $cfgnmcnt++;
                            prt( "$cfgnmcnt: CFG Name: [$tmp]\n");
                       } elsif ($line =~ /^End\s+Source\s+File\s*$/) {
                            $bgnsrc = 0;
                       } elsif ($line =~ /^Begin\s+Source\s+File\s*$/) {
                            $bgnsrc = 1;
                       } elsif ($line =~ /^Begin\s+Custom\s+Build\s+(.+)\s*$/) {
                           $custom = $1;
                       } elsif ($line =~ /^End\s+Custom\s+Build\s*$/) {
                           $custom = '';
                           $customstg = '';
                       } elsif ($line =~ /^Begin Special Build Tool$/) {
                           $special = 1;
                           $specstg = '';
                          # # Begin Special Build Tool
                          # OutDir=.\Release
                          # SOURCE="$(InputPath)"
                          # PostBuild_Cmds=$(outdir)\VisualPng.exe ..\..\contrib\pngsuite\basn6a16.png
                          # # End Special Build Tool
                       } elsif ($line =~ /^End Special Build Tool$/) {
                           $special = 0;
                       } elsif ($line =~ /^PROP\s+(.+)\s*$/) {
                           $prop = $1;
                           $have_prop = 1;
                           # ALL THE '# PROP ' TYPE ENTRIES
                       } elsif ($line =~ /^End\s+Group\s*$/) {
                           $group = ''; # clear GROUP
                           $flist = ''; # and clear FILTER list
                           $in_group = 0; # and NOT in group
                       } elsif ($line =~ /^Begin\s+Group\s+(.+)\s*$/) {
                            # # Begin Group "Source Files"
                            $group = strip_quotes($1);   # usually with quotes
                            $in_group = 1;
                        } else {
                            # ==================================
                            if ($special) {
                                $specstg .= "\n" if (length($specstg));
                                $specstg .= $line;
                            } elsif (length($custom)) {
                                $customstg .= "\n" if (length($customstg));
                                $customstg .= $line;
                            } elsif ($bgnsrc) {
                                if ($line =~ /^SOURCE=(.+)$/) {
                                    $var = $1;
                                    #                     0     1       2       3  4
                                    # push(@{$src_ref}, [ $src, $group, $flist, 0, '' ]); # and PUSH onto SOURCE stack
                                    # push(@dsp_sources,  [ $var, $group, $flist, 0, '' ]);
                                    set_group_and_filter($var, \$group, \$flist);
                                    push(@dsp_sources, [ $var, $group, $flist, 0, '' ]);
                                } else {
                                    pgm_exit(1,"ERROR: Unhandled in source line [$oline] [$line]\n");
                                }
                            } else {
                                pgm_exit(1,"ERROR: Unhandled in target line [$oline] [$line]\n");
                            }
                        }
                    }
                } else {
                    # Items BEFORE '# Begin Target'
                    if ($line =~ /^Begin\s+Target\s*$/) {
                        $in_target = 1;
                    } else {
                       # if ($oline =~ /^(\w+{1})(.+)=(.+)$/ ) 
                       if ($oline =~ /^(\w+)\s*=\s*(.+)\s*$/) {
                            # got something=that, but can be
                            # LIB32=link.exe -lib
                            $key = $1;
                            $var = $2;
                            # have a MACRO A=B
                        } else {
                            $base = 0;
                            $add = 0;
                            if ($line =~ /^PROP\s+(.+)$/) {
                                $prop = $1; # Setup PROPS
                                $have_prop = 1;
                            } elsif ($line =~ /^ADD\s+(.+)$/) {
                                $line = $1; # Adds
                                $add = 1;
                            } elsif ($line =~ /^SUBTRACT\s+(.+)$/) {
                                $line = $1; # Subtracts
                                $add = -1;
                            } else {
                               pgm_exit(1,"ERROR: Unhandled pre Begin Target marker! [$oline] [$line]\n");
                            }
                            if ($add != 0) {
                                if ($line =~ /^BASE\s+/) {
                                     $line =~ s/^BASE\s+//;
                                     $base = 1;
                                }
                                if ($line =~ /^CPP\s+/) {
                                    $line =~ s/^CPP\s+//;
                                    process_config_stg2($rh,$line,$add);
                                } elsif ($line =~ /^RSC\s+/) {
                                    $line =~ s/^RSC\s+//;
                                    # 2010-01-19 IS NEEDED - like
                                    # c:\FG\32\zips\temp\pthread.dsp
                                    # # ADD BASE RSC /l 0x809 /d "NDEBUG"
                                    # # ADD RSC /l 0x809 /d "NDEBUG" /d "PTW32_RC_MSC"
                                    # OR LIKE - c:\FG\32\lpng\projects\visualc6\libpng.dsp
                                    # # ADD RSC /l 0x409 /i "..\.." /d "_DEBUG" /d PNG_DEBUG=1
                                    # # ADD RSC /l 0x409 /i "..\.." /d "NDEBUG" /d PNG_LIBPNG_SPECIALBUILD=""""Use MMX instructions""""
                                    # # ADD RSC /l 0x409 /i "..\.." /d "NDEBUG" /dPNG_LIBPNG_DLLFNAME_POSTFIX=""""VB"""" /dPNG_LIBPNG_SPECIALBUILD=""""__stdcall calling convention used for exported functions""""
                                } elsif ($line =~ /^BSC32\s+/) {
                                } elsif ($line =~ /^LINK32\s+/) {
                                    $line =~ s/^LINK32\s+//;
                                    process_library_stg2($rh,$line,$add);
                                } elsif ($line =~ /^MTL\s+/) {
                                } elsif ($line =~ /^LIB32\s+/) {
                                    $line =~ s/^LIB32\s+//;
                                    prtw("WARNING: LIB32 [$line] DISCARDED\n");
                                } elsif ($line =~ /^F90\s+/) {
                                } else {
                                   pgm_exit(1,"ERROR: Unhandled ADD/SUBTRACT pre Begin Target marker! [$oline] [$line]\n");
                                }
                            }
                        }
                    }
                }
            } else {
                # Items BEFORE '# Begin Project'
                if ($line =~ /^Begin\s+Project\s*$/) {
                    $in_project = 1;
                } else {
                    if ($line =~ /^Microsoft\s+Developer\s+Studio\s+Generated\s+Build\s+File,\s+Format\s+Version\s+(.+)\s*$/) {
                        $version = $1;
                    } elsif (($line =~ /^\*\*\s+DO\s+NOT\s+EDIT\s+\*\*\s*$/)||
                        ($line =~ /\*\* NICHT BEARBEITEN \*\*/)) {
                        # skip it
                    } elsif ($line =~ /^!MESSAGE/) {
                        # skip these
                    } elsif ($line =~ /^TARGTYPE\s+"(.+)"\s+(.+)\s*$/) {
                        $tmp = $1;
                        $targnum = $2;
                        push(@targtypes, $tmp);   # set target type string - san double quotes
                        $targtcnt++;
                        if (length($targtype1) == 0) {
                            # DSP TYPES 0      1    2            3
                            # TARGTYPE "Win32 (x86) Application" 0x0101
                            # TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102
                            # TARGTYPE "Win32 (x86) Console Application" 0x0103
                            # TARGTYPE "Win32 (x86) Static Library" 0x0104
                            @arr = split(/\s/,$tmp);
                            $tmp2 = scalar @arr;
                            for ($k = 2; $k < $tmp2; $k++) {
                                $targtype1 .= ' ' if length($targtype1);
                                $targtype1 .= $arr[$k];
                            }
                            ${$rh}{'PROJECT_APTP'} = $targtype1;
                            prt("$targtcnt: TARGTYPE = [$tmp] num [$targnum]\n");
                        }
                   } elsif ($line =~ /^CFG=(.+)$/) {
                       # default config
                   } else {
                       pgm_exit(1,"ERROR: Unhandled pre Begin Project marker! [$oline]\n");
                   }
               }
            }
        } else {
            # this should be the FIRST line in the file
            if ($line =~ /^\#\s+Microsoft\s+Developer\s+Studio\s+Project\s+File\s+-\s+Name="(.+)"\s+-\s+/) {
               $projname = $1;
               prt("Project name = [$projname]\n");
               $got_project = 1;
               ${$rh}{'PROJECT_NAME'} = $projname;
            }
            # ignore ALL lines before the above FIRST
        }
        if ($have_prop) {
            $have_prop = 0;
            # ALL THE '# PROP ' TYPE ENTRIES
            if ($prop =~ /^BASE\s+/) {
                 $prop = substr($prop,5);
                 $base = 1;
            }
            if ($prop =~ /^Default_Filter\s+(.+)$/) {
                 # PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"
                 # PROP Default_Filter "h;hpp;hxx;hm;inl"
                 # PROP Default_Filter ""
                 $flist = strip_quotes($1);
            } elsif ($prop =~ /^Target_Dir\s+(.+)$/) {
                 # PROP BASE Target_Dir ""
                 # PROP Target_Dir ""
                 $tdir = strip_quotes($1);
            } elsif ($prop =~ /^Ignore_Export_Lib\s+(.+)$/) {
                 # PROP Ignore_Export_Lib 0
                 $igexlib = $1;
            } elsif ($prop =~ /^Intermediate_Dir\s+(.+)$/) {
                 # PROP BASE Intermediate_Dir "Release"
                 # PROP Intermediate_Dir "Release"
                 # PROP BASE Intermediate_Dir "Debug"
                 # PROP Intermediate_Dir "Debug"
                 $intdir = strip_quotes($1);
            } elsif ($prop =~ /^Output_Dir\s+(.+)$/) {
                 # PROP BASE Output_Dir "Debug"
                 # PROP Output_Dir "Debug"
                 # PROP BASE Output_Dir "Release"
                 # PROP Output_Dir "Release"
                 $outdir = strip_quotes($1);
            } elsif ($prop =~ /^Use_Debug_Libraries\s+(.+)$/) {
                 # PROP BASE Use_Debug_Libraries 0
                 # PROP Use_Debug_Libraries 0
                 # PROP BASE Use_Debug_Libraries 1
                 # PROP Use_Debug_Libraries 1
            } elsif ($prop =~ /^Use_MFC\s+(.+)$/) {
                 # PROP BASE Use_MFC 0
                 # PROP Use_MFC 0
            } elsif ($prop =~ /^AllowPerConfigDependencies\s+(.+)$/) {
                 # PROP AllowPerConfigDependencies 0
            } elsif ($prop =~ /^Scc_ProjName\s+(.+)$/) {
                 # PROP Scc_ProjName ""
            } elsif ($prop =~ /^Scc_LocalPath\s+(.+)$/) {
                 # PROP Scc_LocalPath ""
            } elsif ($prop =~ /^Exclude_From_Build\s+(.+)$/) {
                 # PROP Exclude_From_Build 1
                 $exfrmbld = $1;
            } else {
                 pgm_exit(1,"ERROR: Uncased PROP [$prop] [$oline]\n");
            }
        }
    }

    ${$rh}{'PROJECT_SRCS'} = \@dsp_sources;

    prt("Done $lncnt lines from [$file] file...\n");
    show_name_and_type($rh);

    ### pgm_exit(1,"TEMP EXIT");
    return $rh;
}

sub process_dsp_file($) {
    my ($dsp) = @_;
    my $dsp_ref_hash = get_def_dsp_hash_ref($dsp);
    my @dsp_sources = (); # collect DSP source files
    if (! open INF, "<$dsp") {
        prt("ERROR: Unable to open [$dsp] file!\n");
        pgm_exit(1,"");
   }
    my @lines = <INF>;
    close INF;
    return scan_dsp_file_lines($dsp,\@lines);
}

sub process_dsp_file_ok_but($) {
    my ($dsp) = @_;
    my $dsp_ref_hash = get_def_dsp_hash_ref($dsp);
    my @dsp_sources = (); # collect DSP source files
    if (! open INF, "<$dsp") {
        prt("ERROR: Unable to open [$dsp] file!\n");
        pgm_exit(1,"");
   }
    my @lines = <INF>;
    close INF;
    my $lncnt = scalar @lines;
    prt("Processing $lncnt lines from [$dsp] file...\n");
    my ($gotdsp,$lnn,$projname,$targnum);
    my ($key,$var,$curr_cfg,$bgntarg,$bgnproj,$bgnsrc,$group);
    my ($custom,$prop,$version,$cfgnmcnt,$cfgnm,$add);
    my ($cpp,$rsc,$bsc32,$link32,$customstg,$mtl,$lib32,$f90);
    my ($base,$line,$oline,@arr);
    my ($cfg_proj,$cfg_name,$cfg_plat,$cfg_type,$tmp);
    my ($flist,$tdir,$igexlib,$intdir,$outdir,$exfrmbld);
    my ($special,$specstg);
    my ($k,$tmp2,$isdebug);
    my (@targtypes,$targtcnt,$targtype1);
    my ($dsp_sub_sub,$rcfgs,$var1,$msg);
    my ($ingroup);
    @targtypes = ();  # multiple target types
    $targtcnt = 0;    # count of found
    $targtype1 = '';  # although DSP can support multiple types, keep only the first

    $isdebug = 0;
    $gotdsp = 0;
    $lnn = 0;
    $bgntarg = 0;
    $bgnproj = 0;
    $bgnsrc = 0;
    $curr_cfg = ''; # full string
    $group = '';
    $custom = '';
    $customstg = '';
    $prop = '';
    $version = '';
    $cfgnmcnt = 0;
    $add = 0;
    $cpp = '';
    $rsc = '';
    $bsc32 = '';
    $link32 = '';
    $lib32 = '';
    $f90 = '';
    $base = 0;
    #my %cfgnms = ();
    my %cfgnames = ();
    my $cfgnamcnt = 0;
    my $ref_tools = get_tool_set_ref();
    $special = 0;  # Begin to End Special Build Tool
    $specstg = '';
    $ingroup = 0;
    $group = '';   # group name
    $flist = '';   # filter list for group
    ${$dsp_ref_hash}{'TEMP_GOT_LAST'} = 0;
    foreach $oline (@lines) {
        $lnn++;
        chomp $oline;
        $oline = substr($oline,0,length($oline)-1) while ($oline =~ /\s$/);
        next if (length($oline) == 0);
        $line = $oline;
        $add = 0;
        $base = 0;
        if ($gotdsp) {
            if ($line =~ /^\#\s+/) {
                # $line = substr($line,2);
                $line =~ s/^\#\s+//;
                $add = 0;
                $base = 0;
                if ($line =~ /^ADD /) {
                  $add = 1;
                  $line = substr($line, 4);
               } elsif ($line =~ /^SUBTRACT /) {
                  $add = -1;
                  $line = substr($line, 9);
               }
               if ($line =~ /^BASE\s+/) {
                  $base = 1;
                  $line = substr($line, 5);
               }
               # Now process the line
               if ($line =~ /^TARGTYPE\s+"(.+)"\s+(.+)\s*$/) {
                  $tmp = $1;
                  $targnum = $2;
                  push(@targtypes, $tmp);   # set target type string - san double quotes
                  $targtcnt++;
                  if (length($targtype1) == 0) {
                     # DSP TYPES 0      1    2            3
                     # TARGTYPE "Win32 (x86) Application" 0x0101
                     # TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102
                     # TARGTYPE "Win32 (x86) Console Application" 0x0103
                     # TARGTYPE "Win32 (x86) Static Library" 0x0104
                     @arr = split(/\s/,$tmp);
                     $tmp2 = scalar @arr;
                     for ($k = 2; $k < $tmp2; $k++) {
                        $targtype1 .= ' ' if length($targtype1);
                        $targtype1 .= $arr[$k];
                     }
                     ${$dsp_ref_hash}{'PROJECT_APTP'} = $targtype1;
                  }
                  prt("$targtcnt: TARGTYPE = [$tmp] num [$targnum]\n");
               } elsif ($line =~ /^Microsoft\s+Developer\s+Studio\s+Generated\s+Build\s+File,\s+Format\s+Version\s+(.+)\s*$/) {
                  $version = $1;
               } elsif (($line =~ /^\*\*\s+DO\s+NOT\s+EDIT\s+\*\*\s*$/)||
                  ($line =~ /\*\* NICHT BEARBEITEN \*\*/)) {
                  # skip it
               } elsif ($line =~ /^Begin\s+Target\s*$/) {
                  $bgntarg = 1;
               } elsif ($line =~ /^Begin\s+Project\s*$/) {
                  $bgnproj = 1;
               } elsif ($line =~ /^End\s+Target\s*$/) {
                  $bgntarg = 0;
               } elsif ($line =~ /^End\s+Project\s*$/) {
                  $bgnproj = 0;
               } elsif ($line =~ /^End\s+Source\s+File\s*$/) {
                  $bgnsrc = 0;
               } elsif ($line =~ /^Begin\s+Source\s+File\s*$/) {
                  $bgnsrc = 1;
               } elsif ($line =~ /^Begin\s+Group\s+(.+)\s*$/) {
                  # # Begin Group "Source Files"
                  $group = strip_quotes($1);   # usually with quotes
                  $ingroup = 1;
               } elsif ($line =~ /^End\s+Group\s*$/) {
                  $group = '';
                  $ingroup = 0;
               } elsif ($line =~ /^Begin\s+Custom\s+Build\s+(.+)\s*$/) {
                  $custom = $1;
               } elsif ($line =~ /^End\s+Custom\s+Build\s*$/) {
                  $custom = '';
                  $customstg = '';
               } elsif ($line =~ /^Begin Special Build Tool$/) {
                  $special = 1;
                  $specstg = '';
                  # # Begin Special Build Tool
                  # OutDir=.\Release
                  # SOURCE="$(InputPath)"
                  # PostBuild_Cmds=$(outdir)\VisualPng.exe ..\..\contrib\pngsuite\basn6a16.png
                  # # End Special Build Tool
               } elsif ($line =~ /^End Special Build Tool$/) {
                  $special = 0;
               } elsif ($line =~ /^PROP\s+(.+)\s*$/) {
                  $prop = $1;
                  # ALL THE '# PROP ' TYPE ENTRIES
                  if ($prop =~ /^BASE\s+/) {
                     $prop = substr($prop,5);
                     $base = 1;
                  }
                  if ($prop =~ /^Default_Filter\s+(.+)$/) {
                     # PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"
                     # PROP Default_Filter "h;hpp;hxx;hm;inl"
                     # PROP Default_Filter ""
                     $flist = strip_quotes($1);
                  } elsif ($prop =~ /^Target_Dir\s+(.+)$/) {
                     # PROP BASE Target_Dir ""
                     # PROP Target_Dir ""
                     $tdir = strip_quotes($1);
                  } elsif ($prop =~ /^Ignore_Export_Lib\s+(.+)$/) {
                     # PROP Ignore_Export_Lib 0
                     $igexlib = $1;
                  } elsif ($prop =~ /^Intermediate_Dir\s+(.+)$/) {
                     # PROP BASE Intermediate_Dir "Release"
                     # PROP Intermediate_Dir "Release"
                     # PROP BASE Intermediate_Dir "Debug"
                     # PROP Intermediate_Dir "Debug"
                     $intdir = strip_quotes($1);
                  } elsif ($prop =~ /^Output_Dir\s+(.+)$/) {
                     # PROP BASE Output_Dir "Debug"
                     # PROP Output_Dir "Debug"
                     # PROP BASE Output_Dir "Release"
                     # PROP Output_Dir "Release"
                     $outdir = strip_quotes($1);
                  } elsif ($prop =~ /^Use_Debug_Libraries\s+(.+)$/) {
                     # PROP BASE Use_Debug_Libraries 0
                     # PROP Use_Debug_Libraries 0
                     # PROP BASE Use_Debug_Libraries 1
                     # PROP Use_Debug_Libraries 1
                  } elsif ($prop =~ /^Use_MFC\s+(.+)$/) {
                     # PROP BASE Use_MFC 0
                     # PROP Use_MFC 0
                  } elsif ($prop =~ /^AllowPerConfigDependencies\s+(.+)$/) {
                     # PROP AllowPerConfigDependencies 0
                  } elsif ($prop =~ /^Scc_ProjName\s+(.+)$/) {
                     # PROP Scc_ProjName ""
                  } elsif ($prop =~ /^Scc_LocalPath\s+(.+)$/) {
                     # PROP Scc_LocalPath ""
                  } elsif ($prop =~ /^Exclude_From_Build\s+(.+)$/) {
                     # PROP Exclude_From_Build 1
                     $exfrmbld = $1;
                  } else {
                     pgm_exit(1,"ERROR: Uncased PROP [$prop] [$oline]\n");
                  }
               } elsif ($line =~ /^Name\s+(.+)\s*$/) {
                   # elsif ($line =^ /^Name\s+-\s+(.+)\s*$/)
                  $cfgnm = strip_quotes($1);
                  # like from
                  # # Begin Target
                  # # Name - "FlightGear - Win32 Release"
                  # # Name "minigzip - Win32 DLL Release"
                  # # Name "minigzip - Win32 DLL ASM Release"
                  # etc
                  # # Begin Group "Source Files"
                  $cfgnm =~ s/^-\s+//; # dump any '- ' lead
                  $cfgnm = strip_quotes($cfgnm);
                  $cfgnmcnt++;
                  prt( "$cfgnmcnt: CFG Name: [$cfgnm]\n");
                  check_cfg_name($dsp_ref_hash, $cfgnm, \%cfgnames, $cfgnamcnt );
               } elsif ($line =~ /^CPP /) {
                   $msg = '';
                   $msg .= 'BASE ' if ($base);
                   if ($add) {
                       if ($add == -1) {
                           $msg .= 'SUBTRACT ';
                       } else {
                           $msg .= 'ADD '
                       }
                   }
                   $msg .= 'CPP ';
                  # ADD CPP /nologo /MD /W3 /GR /GX /O2 \
                  # /I ".." /I "src" /I "src\include" /I "src\FDM\JSBsim" /I "..\SimGear" \
                  # /I "..\zlib-1.2.3" /I "..\freeglut\include" /I "C:\Program Files\OpenAL 1.1 SDK\include" \
                  # /I "..\OpenSceneGraph\include" /I "..\OpenThreads\include" /I "..\pthreads" \
                  # /I "..\alut\include" \
                  # /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "WIN32" /D "NDEBUG" /D "_CONSOLE" 
                  # /D "_CRT_SECURE_NO_WARNINGS" /D "_USE_MATH_DEFINES" /D "_CRT_SECURE_NO_DEPRECATE" \
                  # /D "HAVE_CONFIG_H" /D "FGFS" /D "FG_NEW_ENVIRONMENT" /D "ENABLE_AUDIO_SUPPORT" \
                  # /D "ENABLE_PLIB_JOYSTICK" /D "ENABLE_THREADS" /D "FREEGLUT_STATIC" \
                  # /D "NOMINMAX" /D "OPENALSDK" /FD /c
                  $cpp = substr($line,4);
                  prt("$msg [$cpp]\n");
                  process_config_stg($dsp_ref_hash,$cpp);
               } elsif ($line =~ /^RSC\s+(.+)$/) {
                   $rsc = $1;
               } elsif ($line =~ /^BSC32 /) {
                  $bsc32 = substr($line,6);
               } elsif ($line =~ /^LINK32 /) {
                   $msg = '';
                   $msg .= 'BASE ' if ($base);
                   if ($add) {
                       if ($add == -1) {
                           $msg .= 'SUBTRACT ';
                       } else {
                           $msg .= 'ADD '
                       }
                   }
                   $msg .= 'LINK ';
                   # # 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 odbc32.lib \
                   # odbccp32.lib comctl32.lib Msimg32.lib Winmm.lib ws2_32.lib SimGear.lib \
                   # sg.lib pui.lib puAux.lib fnt.lib net.lib ul.lib js.lib zlib.lib osg.lib \
                   # osgDB.lib osgText.lib osgUtil.lib OpenThreads.lib OpenAL32.lib alut.lib \
                   # pthreadVC2.lib osgViewer.lib osgGA.lib osgParticle.lib \
                   # /libpath:"..\SimGear\$(IntDir)" /libpath:"..\PLIB" \
                   # /libpath:"..\zlib-1.2.3\projects\visualc6\Win32_LIB_Release" \
                   # /libpath:"..\OpenSceneGraph\lib" /libpath:"..\OpenThreads\lib\Win32" \
                   # /libpath:"C:\Program Files\OpenAL 1.1 SDK\libs\Win32" \
                   # /libpath:"..\alut\admin\VisualStudioDotNET\alut\$(IntDir)" \
                   # /libpath:"..\freeglut\$(IntDir)Static" /libpath:"..\pthreads" \
                   # /libpath:"..\3rdparty\lib" /nologo /subsystem:console /machine:I386 \
                   # /out:Release\FlightGear.exe
                  $link32 = substr($line,7);
                  prt("$msg [$link32]\n");
               } elsif ($line =~ /^MTL /) {
                  $mtl = substr($line, 4);
               } elsif ($line =~ /^LIB32 /) {
                  $lib32 = substr($line,6);
               } elsif ($line =~ /^F90 /) {
                  # ADD BASE F90 /compile_only /nologo /warn:nofileopt
                  $f90 = substr($line,4);
               } else {
                  pgm_exit(1, "ERROR: $lnn: [$oline]\n [$line]\n cfg=$curr_cfg - CHECK ME#! NOT CODED!!\n");
               }
        } else {
           if ($line =~ /^!MESSAGE/) {
              $line = substr($line,8);
              # skip most message lines, but it does give a LIST of CONFIGURATIONS
              # !MESSAGE "minigzip - Win32 DLL Release" (based on "Win32 (x86) Console Application")
              # !MESSAGE "minigzip - Win32 DLL Debug" (based on "Win32 (x86) Console Application")
              # !MESSAGE "minigzip - Win32 DLL ASM Release" (based on "Win32 (x86) Console Application")
              # etc
              @arr = space_split($line);
              if ($line =~ /^\s*"/) {
                 $tmp = $arr[-1];  # get last
                 $tmp = $arr[-2] if ($tmp eq ')');
                 $tmp =~ s/\)$//;  # strip ')' tail
                 $tmp = strip_quotes($tmp); # and quotes
                 if (length($tmp) && ($tmp =~ /\S/)) {
                     check_targ_type( $tmp, \@targtypes, $targtcnt );
                 } else {
                     prt("Got array ");
                     foreach  (@arr) {
                         prt("[$_] ");
                     }
                     pgm_exit(1,"FAILED ON [$line]\n");
                 }
                 $tmp2 = strip_quotes($arr[0]);
                 if (defined $cfgnames{$tmp2}) {
                    pgm_exit(1, "ERROR: Duplicated CONFIG NAME! [$tmp2]\n");
                 } else {
                    # accumulate CFG names, into hash, keeping count
                    $cfgnamcnt++;
                    $cfgnames{$tmp2} = $cfgnamcnt;
                 }
                 if ($dbg_02) {
                    prt("Check out a SPACE split [$line]...\n");
                    foreach $tmp (@arr) {
                       prt("$tmp\n");
                    }
                    pgm_exit(1,"CHECK SPLIT!");
                 }
              }
           } elsif ($line =~ /^(\w+)\s*=\s*(.+)\s*$/) {
              # got something=that, but can be
              # LIB32=link.exe -lib
              $key = $1;
              $var = $2;
              #@arr = split(/\s/,$var);
              #$var = $arr[0];
              if ($special) {
                 $specstg .= "\n" if (length($specstg));
                 $specstg .= $line;
              } elsif (length($custom)) {
                 $customstg .= "\n" if (length($customstg));
                 $customstg .= $line;
              } else {
                 # # Begin Target
                 # # Name - "find_window - Win32 Release"
                 # # Name - "find_window - Win32 Debug"
                 # # Begin Group "Source Files"
                 # # PROP Default_Filter "cpp;c;cxx;def;odl;idl;hpj;bat;asm;asmx"
                 # # Begin Source File
                 # SOURCE=.\find_ABT.cpp
                 # # End Source File
                 if ($key eq 'SOURCE') {
                    # SOURCE FILE
                    if ($bgnsrc) {
                       #                     0     1       2       3  4
                       # push(@{$src_ref}, [ $src, $group, $flist, 0, '' ]); # and PUSH onto SOURCE stack
                       push(@dsp_sources,  [ $var, $group, $flist, 0, '' ]);
                    } else {
                       pgm_exit(1,"ERROR: $lnn: key [$key] = [$var] OUTSIDE BEGIN SOURCE\n[$oline]\n");
                    }
                 } else {
                    if (defined ${$ref_tools}{$key}) {
                       ${$ref_tools}{$key} = $var;
                    } else {
                       pgm_exit(1, "ERROR:$lnn: key [$key] = [$var] NOT IN 'tools' set\n[$oline]\n");
                    }
                 }
              }
           } elsif ($line =~ /^!IF\s+"\$\(CFG\)"\s+==\s+"(.+)"\s*$/) {
              $tmp = $1;
              prtw("WARNING: Discarded CONFIG [$curr_cfg]!\n") if (length($curr_cfg));       
              $curr_cfg = $tmp;
              # "Spy5 - Win32 Debug" or
              # "minigzip - Win32 DLL ASM Release"
              if ($curr_cfg =~ /Debug/i) {
                 $tmp2 = "Debug";
                 $isdebug = 1;
                 $dsp_sub_sub = get_default_sub3(1);
              } elsif ($curr_cfg =~ /Release/i) {
                 $tmp2 = "Release";
                 $isdebug = 0;
                 $dsp_sub_sub = get_default_sub3(0);
              } elsif ($curr_cfg =~ /DLL/) {  # exception for DLL
                 $tmp2 = "ReleaseDLL";
                 $isdebug = 0;
                 $dsp_sub_sub = get_default_sub3(0);
              } else {
                 pgm_exit(1,"ERROR: Did NOT find 'Debug' or 'Release' in [$curr_cfg]!\n");
              }
              @arr = split(/\s/,$curr_cfg);
              $tmp = scalar @arr;
              if ($tmp < 4) {
                 pgm_exit(1,"ERROR: UNmanaged split of [$curr_cfg]. Expected min 4, got $tmp! FIX CODE!\n");
              }
              $cfg_proj = $arr[0];
              $cfg_plat = $arr[2]; # Platform
              $cfg_type = $arr[3]; # Release, Debug, etc 'DLL Universal Unicode Release', or ...
              $cfg_name = $cfg_type;
              # from : C:\FG\27\wxWidgets-2.8.10\build\msw\wx_adv.dsp
              # adv - Win32 DLL Universal Unicode Release
              if ($tmp > 4) {
                 $cfg_type = '';
                 for ($k = 3; $k < $tmp; $k++) {
                    if (($arr[$k] =~ /Release/i)||($arr[$k] =~ /Debug/i)) {
                       $cfg_type = $arr[$k];
                       $arr[$k] = '';
                    }
                 }
                 $cfg_type = 'Release' if (length($cfg_type)==0);
                 $cfg_name = $cfg_type;
                 for ($k = 3; $k < $tmp; $k++) {
                    $cfg_type .= $arr[$k];
                 }
              }
              if ($bgntarg) {
                  # change of CFG item for a specific source - NOT HANDLED
              } else {
                  prt("[dbg_01] Enter CFG [$curr_cfg] [$cfg_name]\n") if ($dbg_01);
                  check_cfg_name($dsp_ref_hash, $curr_cfg, \%cfgnames, $cfgnamcnt );
                  $var1 = "-NEW_OUTD-";
                  $tmp2 = "$cfg_type|$cfg_plat";
                  $rcfgs = ${$dsp_ref_hash}{'PROJECT_CFGS'};
                  #                   0       1      2      3
                  # push(@{$rcfgs}, [ $pname, $var1, $conf, $dsp_sub_sub ]);
                  push(@{$rcfgs}, [ $cfg_name, $var1, $tmp2, $dsp_sub_sub ]);
                  ${$dsp_ref_hash}{'TEMP_LAST_CFG'} = ${$rcfgs}[-1];
                  ${$dsp_ref_hash}{'TEMP_GOT_LAST'} = 1;
              }
           } elsif ($line =~ /^!ELSEIF\s+"\$\(CFG\)"\s+==\s+"(.+)"\s*$/) {
              $curr_cfg = $1;
              if ($curr_cfg =~ /Debug/i) {
                 $tmp2 = "Debug";
                 $isdebug = 1;
                 $dsp_sub_sub = get_default_sub3(1);
              } elsif ($curr_cfg =~ /Release/i) {
                 $tmp2 = "Release";
                 $isdebug = 0;
                 $dsp_sub_sub = get_default_sub3(0);
              } elsif ($curr_cfg =~ /DLL/) {  # exception for DLL
                 $tmp2 = "ReleaseDLL";
                 $isdebug = 0;
                 $dsp_sub_sub = get_default_sub3(0);
              } else {
                 pgm_exit(1,"ERROR: Did NOT find 'Debug' or 'Release' in [$curr_cfg]!\n");
              }
              @arr = split(/\s/,$curr_cfg);
              $tmp = scalar @arr;
              if ($tmp < 4) {
                 pgm_exit(1,"ERROR: UNmanaged split of [$curr_cfg]. Expected min 4, got $tmp! FIX CODE!\n");
              }
              $cfg_proj = $arr[0];
              $cfg_plat = $arr[2]; # Platform
              $cfg_type = $arr[3]; # Release, Debug, etc 'DLL Universal Unicode Release', or ...
              $cfg_name = $cfg_type;
              # from : C:\FG\27\wxWidgets-2.8.10\build\msw\wx_adv.dsp
              # adv - Win32 DLL Universal Unicode Release
              if ($tmp > 4) {
                 $cfg_type = '';
                 for ($k = 3; $k < $tmp; $k++) {
                    if (($arr[$k] =~ /Release/i)||($arr[$k] =~ /Debug/i)) {
                       $cfg_type = $arr[$k];
                       $arr[$k] = '';
                    }
                 }
                 $cfg_type = 'Release' if (length($cfg_type)==0);
                 $cfg_name = $cfg_type;
                 for ($k = 3; $k < $tmp; $k++) {
                    $cfg_type .= $arr[$k];
                 }
              }
              if ($bgntarg) {
                  # change of CFG item for a specific source - NOT HANDLED

              } else {
                  prt("[dbg_01] Elsif CFG [$curr_cfg] [$cfg_name]\n") if ($dbg_01);
                  check_cfg_name($dsp_ref_hash, $curr_cfg, \%cfgnames, $cfgnamcnt );
                  $var1 = "-NEW_OUTD-";
                  $tmp2 = "$cfg_type|$cfg_plat";
                  $rcfgs = ${$dsp_ref_hash}{'PROJECT_CFGS'};
                  #                   0       1      2      3
                  # push(@{$rcfgs}, [ $pname, $var1, $conf, $dsp_sub_sub ]);
                  push(@{$rcfgs}, [ $cfg_name, $var1, $tmp2, $dsp_sub_sub ]);
                  ${$dsp_ref_hash}{'TEMP_LAST_CFG'} = ${$rcfgs}[-1];
                  ${$dsp_ref_hash}{'TEMP_GOT_LAST'} = 1;
              }
           } elsif ($line =~ /^!ENDIF\s*$/) {
              if ($bgntarg) {
                  # end in source config change
              } else {
                  prt("[dbg_01] Endif CFG [$curr_cfg]\n") if ($dbg_01);
              }
              $curr_cfg = ''; # set to NOTHING
              ${$dsp_ref_hash}{'TEMP_GOT_LAST'} = 0;
           } else {
              if (length($custom)) {
                 $customstg .= "\n" if (length($customstg));
                 $customstg .= $line;
              } else {
                 prt( "$lnn: [$line] CHECK ME2!!!\n");
              }
           }
        }
     } else {
        if ($line =~ /^\#\s+Microsoft\s+Developer\s+Studio\s+Project\s+File\s+-\s+Name="(.+)"\s+-\s+/) {
           $projname = $1;
           prt("Project name = [$projname]\n");
           $gotdsp = 1;
           ${$dsp_ref_hash}{'PROJECT_NAME'} = $projname;
        }
     }
    }
   #$key = 'PROJECT_CFGS';
   # if (defined ${$rh}{$key}) {
   #     $rcfgs = ${$rh}{$key};
   #     $cnt = scalar @{$rcfgs};
   ${$dsp_ref_hash}{'PROJECT_SRCS'} = [ @dsp_sources ];

   show_name_and_type($dsp_ref_hash);

   prt("Done [$dsp] file scanning...\n");
   ### pgm_exit(1,"TEMP EXIT");
   return $dsp_ref_hash;
}

sub process_dsp_list($) {
   my ($fil) = @_;
   if (open DL, "<$fil") {
      my @lines = <DL>;
      close DL;
      my $max = scalar @lines;
      my $cnt = 0;
      foreach my $line (@lines) {
         chomp $line;
         $cnt++;
         prt("$cnt of $max: $line\n");
         my $rh = process_dsp_file($line);
         my ($name,$dir) = fileparse($line);
         my $tmp_out = "temp.$name.dsp";
         if ( write_hash_to_DSP3( $tmp_out, $rh, 0 ) ) {
            prt( "From [$line]\nOK, written $tmp_out\n" );
         } else {
            prt( "From [$line]\nFAILED on $tmp_out\n" );
         }
      }
   }
}

my $temp_out = 'tempd.dsp';
#my $dbg4write = 0;
my $dbg4write = -1;
my $ref_hash = process_dsp_file($in_file);
my ($nm,$dr,$ext) = fileparse($in_file,, qr/\.[^.]*/);
$temp_out = $perl_root."\\temp.$nm.dsp";

if ( write_hash_to_DSP3( $temp_out, $ref_hash, $dbg4write ) ) {
   prt( "From [$in_file]\nOK written [$temp_out].\n" );
} else {
   prt( "From [$in_file]\nFAILED on [$temp_out]\n" );
}
if ($dbg_03) {
   process_dsp_list('fgdsplist.txt');
}

pgm_exit(0,"Normal exit");

# cmp2dsp C:\GTools\tools\Spy5\Spy5.dsp temp.Spy5.dsp.dsp
# eof - movedsp.pl
