lib_vcscan.pl to HTML.

index -|- end

Generated: Mon Aug 29 19:34:46 2016 from lib_vcscan.pl 2015/04/05 103 KB. text copy

#!/usr/bin/perl -w
# lib_vcscan.pl (was scanvc.pl)
# 20120205 - Try to smooth out choice of REL or DEB, and accept 'Deb' or 'Rel'
# 31/01/2012 - Add show_hash_results4($$), which slectively shows the has contents per a bit flag
# 18/10/2011 - Reduce output, per $dbg flag bits, and added sub adjust_inter_out_dirs($),
# sub adjust_runtime_to($$) and sub adjust_output_name($) to ADJUST the hash
# 20120128 - massage_command3: version 10 vcproj files, and maybe others. can have > instead of '>'
# 25/11/2010 - Support VC10 vcxproj file
# 18/09/2010 - Renamed to lib_vcscan.pl
# 07/07/2010 - Add ability to set debug items - svc_set_dbg_item(val)
# 2010.05/31 - Minor fix to '$cf_dn_no_s' - or in, not '&', and add 'scanvc' to WARNINGS...
# 2010/05/06 - fix bug [dbg_v32] 015:048-059: VCCLCompilerTool:CompileAs: set [-NEW_RT-] from [/MDd] to [/MDd /]
# 2010/05/05 - minor fix for item like '"2">', which should be fixed upstream...
# 2010/05/01 - added 'strict' and 'warnings', and fixed lots of things
# 2010/04/23 - handle different xml lining - added sub get_clean_seek_item($) to ensure trailing '>' also removed
# 2010/03/08 - Remove write tempvcx.xml from scanvc.pl, or only to perl base directory...
# 2010/03/01 - if vcproj contains IgnoreDefaultLibraryNames="MSVCRT", add /nodefaultlib:"MSVCRT" to DSP
#   Add this to the -NEW_OUT- substitution parameter - that is to the # ADD LINK32 line.
#   Can be DIFFERENT per configuration.
# 2010/01/14 = Can be 'Description=""Copy Library to plib directory""' Note double QUOTES as '"', AND '"', OR WORSE!!!
# 2009/10/25 - move out of fgscanvc03.pl
# Subroutine name list - generated by chkperl.pl, on 20091029
# svc_get_dbg_stg(), get_default_ref_hash($), get_item_from_hash($$), get_per_file_hash($), get_last_src_offset($),
# get_current_xline_stg($), get_project_configs($), svc_get_project_name_stg($), get_project_srcs_ref($), add_vs_project_items($$$$),
# extract_curr_items($$$$$$$$$), svc_add_props_to_hash($$$$), add_vs_config_item($), show_hash_results3($), massage_command3($),
# get_line_hash_missed($$$), get_ct_line_hash_missed($$), process_vc_conf_tool_tag($), process_vc_file_tool_tag($),
# get_cfgs_array_order($$), add_any_per_file_items3($), get_xln_stg($$), process_VC_lines($$$), svc_xml_to_lines($$),
# process_VCPROJ3
# === End sub name list ===
use strict;
use warnings;
use File::Basename;  # split path ($name,$dir,$ext) = fileparse($file [, qr/\.[^.]*/] )
use Cwd;

# 2010/05/01 - additions
my %compileas = (
   0 => "",
   1 => "TC",
   2 => "TP"
   );

my $write_temp_xml = 0;     # only really needed for DEBUG, and should be to perl base directory if done...
my $write_temp_xml2 = 1;     # only really needed for DEBUG, and should be to perl base directory if done...
my $sc_last_intdir = '';

# CURR_FLAG values
my $cf_apptype = 0x00000001;    # signal, we have an APP TYPE - VERY IMPORTANT
my $cf_apptyp2 = 0x00000002;    # APP TYPE
my $cf_dn_lt_t = 0x80000000;    # if (!$dn_lt_noo)
my $cf_dn_no_s = 0x40000000;    # DOES NOT CONTAIN(7) 'SubSystem' NOR 'ImportLibrary' only ONCE

my $flist_done_once = 0; # only once for prtw( "WARNING:$xln DOES NOT CONTAIN(12) '$seek'? [$line] [$fil]\n" );
my $g_sc_inconfigs = 0;
my $g_sc_infiles = 0;
my $g_sc_infconf = 0;
my $g_sc_act_vcproj = '';
my ($g_sc_act_name,$g_sc_act_path); # = fileparse($g_sc_act_vcproj);

# DEBUG
my $dbg_v01 = 0;    # prt( "[v01] $xln Bgn VisualStudioProject name=[$val1], type=[$val3], vers=[$val2]\n" ) if ($dbg_v01);
my $dbg_v02 = 0;    # prt( "[v02] $xln Bgn Configurations ($tag)\n" ) if ($dbg_v02);
my $dbg_v03 = 0;    # prt( "[v03] seek=PreprocessorDefinitions = [$ppdefs] [$fil]\n" ) if ($dbg_v03);
my $dbg_v04 = 0;    # prt( "[v04] $xln 'VCCLCompilerTool' DOES NOT CONTAIN(2) 'PreprocessorDefinitions' [$line]\n" ) if ($dbg_v04);
my $dbg_v05 = 0;    # prt( "[v05] $xln 'VCCLCompilerTool' DOES NOT CONTAIN(3) 'RuntimeLibrary' [$line]\n" ) if ($dbg_v05);
my $dbg_v06 = 0;    # prt( "[v06] $xln Bgn ConfigurationName=[$confname] conf=[$conf] [$line] ...($tag)\n" ) if ($dbg_v06);
my $dbg_v07 = 0;    # prt( "[v07] $xln Bgn Filter name=[$fname] list=[$flist] ($tag)\n" ) if ($dbg_v07);
my $dbg_v08 = 0;    # prt( "[v08] $xln Bgn File [$last_src] ($tag)\n" ) if ($dbg_v08);
my $dbg_v09 = 0;    # prt( "[v09] $xln Bgn FileConfiguration [$last_src] ($tag)\n" ) if ($dbg_v09);
my $dbg_v10 = 0;    # prt( "[v10] $xln Last = $last_src=[".${$src_ref}[-1][0]."] $fconf ExcludedFromBuild = $adddefs\n" ) if ($dbg_v10);
my $dbg_v11 = 0;    # prt( "[v11] $xln NO keys in per file hash...\n") if ($dbg_v11);
my $dbg_v12 = 0;    # prt( "[v12] $xln Bgn Files ($tag)\n" ) if ($dbg_v12);
my $dbg_v13 = 0;    # prt( "[v13] $xln 'VCCLCompilerTool' DOES NOT CONTAIN(1) 'AdditionalIncludeDirectories' [$line]\n" ) if ($dbg_v13);
my $dbg_v15 = 0;    # prt( "[v15] $xln got POST event [$ppdefs]\n" ) if ($dbg_v15);
my $dbg_v16 = 0;    # prtw( "WARNING:$xln 'VCCLinkerTool' DOES NOT CONTAIN(4) '$seek' [$line] [$fil]\n" ) if ($dbg_v16);

my $dbg_v20 = 0;    # prt( "[v20] $xln Changed(2) [IntermediateDirectory] from [".${$dsp_sub_sub}{$var2}."] to [".add_quotes($adddeps)."]\n" ) if ($dbg_v20);
my $dbg_v21 = 0;    # prt( "[v21]:lib_vcscan:$xln: 'VCCLinkerTool' DOES NOT CONTAIN(5) 'OutputFile' [$line]\n" ) if ($dbg_v21);
my $dbg_v22 = 0;    # prt( "[v22] $xln seek=AdditionalDependencies: Set [$var1] to [$adddeps]\n" ) if ($dbg_v22);
my $dbg_v23 = 0;    # prt( "[v23] $xln seek=AdditionalLibraryDirectories: Set [$var1] to [$tmp] from [$adddeps]\n" ) if ($dbg_v23);
my $dbg_v24 = 0;    # prt( "[v24] $xln seek=OutputFile: Set [$var2] to [$newval]\n" ) if ($dbg_v24);
my $dbg_v25 = 0;    # prt( "[v25] " ); prt( "$xln VCCLCompilerTool:AdditionalIncludeDirectories: RESET [$var1] to [$newval] from [$curval]\n" );
my $dbg_v26 = 0;    # prt( "[v26] Processing prop file(s) [$fils] cnt=$cnt\n" ) if ($dbg_v26); and MORE
my $dbg_v27 = 0;    # prt( "[v27] $xln got CUSTOM event [$pname] [$fconf] [$adddefs]\n" ) if ($dbg_v27);
my $dbg_v28 = 0;    # prt( "[v28] CUSTOM event [$tmp]\n" ) if ($dbg_v28);
my $dbg_v29 = 0;    # prt( "[v29] $xln Added CUSTOM build for source [$key]\n" ) if ($dbg_v29);
my $dbg_v30 = 0;    # prt( "[v30] CUSTOM build [$tmp]\n" ) if ($dbg_v30);
my $dbg_v31 = 0;    # prt( "[v31] " ); prt( "$xln conf=[$confname]:VCCLCompilerTool: [$line]\n seeks=[$doneseeks]\n missed=[$missed] ($lhlen)\n" );
my $dbg_v32 = 0;    # prt( "[v32] $xln VCCLCompilerTool:CompileAs: set [$var3] to ".${$dsp_sub_sub}{$var3}."\n" ) if ($dbg_v32);
my $dbg_v33 = 0;    # prt( "[v33] $xln Changed(1) [OutputDirectory] from [".${$dsp_sub_sub}{$var1}."] to [".add_quotes($adddeps)."]\n" ) if ($dbg_v33);
my $dbg_v34 = 0;    # prt( "[v34] $xln file: 'VCCLCompilerTool' [$line] IGNORED CHECK ($lhlen)\n" ) if ($dbg_v34); AND 'VCResourceCompilerTool'
my $dbg_v35 = 0;    # prt( "[v35] $xln Project [$projname], APP_TYPE CONFIRMED per 'ImportLibrary' set to [$dnapptype]...\n" ) if ($dbg_v35);
my $dbg_v36 = 0;    # prt("[v36] Got description: [$ppdefs]\n") if ($dbg_v36); and more... 2010/01/14
my $dbg_v37 = 0;    # prt("[v37] Done process_VC_lines...\n") if ($dbg_v37);
my $dbg_v38 = 0;    # prt( "[v38] Processing project [$projname]...\n" ) if ($dbg_v38);
my $dbg_v39 = 0;    # prt( "[v39] $xln seek=IgnoreDefaultLibraryNames: Set [$var1] to [$tmp] from [$adddeps] prev [$curval]\n" ) if ($dbg_v39);
my $dbg_v40 = 0;    # prt("[v40] STORE:$tmp: In rcfgs (ra)[$confname], [$var1], [$conf], & \$dsp_sub_sub ] )\n") if ($dbg_v40); # ONLY STORE OF 'PROJECT_CFGS'
my $dbg_v41 = 0;    # prt( "$xln Project [$projname], APP_TYPE per 'ModuleDefinitionFile' [$apptype]...\n" ) if ($dbg_v41);
my $dbg_v42 = 0;    # prt( "\nProcessing file [$fil], $lncnt lines ($xlncnt) ...\n" );
my $dbg_v43 = 0;    # prt( "[v43] $xln Project [$projname], APP_TYPE RESET per 'SubSystem' [$apptype] from [$dnapptype]...\n" );

# forward
sub svc_xml_to_lines($$);

sub svc_get_dbg_stg() {
    my $dbs = '';
    if ($dbg_v01) { $dbs .= "v01 "; } if ($dbg_v02) { $dbs .= "v02 "; } if ($dbg_v03) { $dbs .= "v03 "; } 
    if ($dbg_v04) { $dbs .= "v04 "; } if ($dbg_v05) { $dbs .= "v05 "; } if ($dbg_v06) { $dbs .= "v06 "; }
    if ($dbg_v07) { $dbs .= "v07 "; } if ($dbg_v08) { $dbs .= "v08 "; } if ($dbg_v09) { $dbs .= "v09 "; }
    if ($dbg_v10) { $dbs .= "v10 "; } if ($dbg_v11) { $dbs .= "v11 "; } if ($dbg_v12) { $dbs .= "v12 "; }
    if ($dbg_v13) { $dbs .= "v13 "; } if ($dbg_v15) { $dbs .= "v15 "; } if ($dbg_v16) { $dbs .= "v16 "; }
    if ($dbg_v20) { $dbs .= "v20 "; } if ($dbg_v21) { $dbs .= "v21 "; } if ($dbg_v22) { $dbs .= "v22 "; } if ($dbg_v23) { $dbs .= "v23 "; }
    if ($dbg_v24) { $dbs .= "v24 "; } if ($dbg_v25) { $dbs .= "v25 "; } if ($dbg_v26) { $dbs .= "v26 "; }
    if ($dbg_v27) { $dbs .= "v27 "; } if ($dbg_v28) { $dbs .= "v28 "; } if ($dbg_v29) { $dbs .= "v29 "; }
    if ($dbg_v30) { $dbs .= "v30 "; } if ($dbg_v31) { $dbs .= "v31 "; } if ($dbg_v32) { $dbs .= "v32 "; }
    if ($dbg_v33) { $dbs .= "v33 "; } if ($dbg_v34) { $dbs .= "v34 "; } if ($dbg_v35) { $dbs .= "v35 "; }
    if ($dbg_v36) { $dbs .= "v36 "; } if ($dbg_v37) { $dbs .= "v37 "; } if ($dbg_v38) { $dbs .= "v38 "; }
    if ($dbg_v39) { $dbs .= "v39 "; } if ($dbg_v40) { $dbs .= "v40 "; } if ($dbg_v41) { $dbs .= "v41 "; } 
    if ($dbg_v42) { $dbs .= "v42 "; } if ($dbg_v43) { $dbs .= "v43 "; } 
    return $dbs;
}
sub svc_set_dbg_val($) {
    my ($v) = shift;
    $dbg_v01 = $v; $dbg_v02 = $v; $dbg_v03 = $v; $dbg_v04 = $v; $dbg_v05 = $v; $dbg_v06 = $v; $dbg_v07 = $v; $dbg_v08 = $v;
    $dbg_v09 = $v; $dbg_v10 = $v; $dbg_v11 = $v; $dbg_v12 = $v; $dbg_v13 = $v; $dbg_v15 = $v; $dbg_v20 = $v; $dbg_v21 = $v; $dbg_v22 = $v;
    $dbg_v23 = $v; $dbg_v24 = $v; $dbg_v25 = $v; $dbg_v26 = $v; $dbg_v27 = $v; $dbg_v28 = $v; $dbg_v29 = $v; $dbg_v30 = $v;
    $dbg_v31 = $v; $dbg_v32 = $v; $dbg_v33 = $v; $dbg_v34 = $v; $dbg_v35 = $v; $dbg_v36 = $v; $dbg_v37 = $v; $dbg_v38 = $v;
    $dbg_v39 = $v; $dbg_v40 = $v; $dbg_v41 = $v; $dbg_v42 = $v; $dbg_v43 = $v;
}
sub svc_set_dbg_on()  { svc_set_dbg_val(1); }
sub svc_set_dbg_off() { svc_set_dbg_val(0); }
sub svc_set_dbg_item($$) {
    my ($val,$of) = @_;
    #if ($val == 40) {
    #    $dbg_v40 = 1;
    #    return 0;
    #}
    my $var = '$dbg_v'.$val;
    prt("Setting var [$var] to [$of]\n");
    my $v = eval $var;
    if (defined $v) {
        my $stg = "$var"." = $of;";
        eval $stg;
        return 0;
    }
    return 1;
}

sub get_default_ref_hash($) {
    my ($fil) = @_;
    my %hash = ();
    my $rh = \%hash;
    my ($nam,$dir,$ext) = fileparse($fil,qr/\.[^.]*/);
    $dir = cwd() if ($dir =~ /^\.(\\|\/)$/);
    $dir .= "\\" if (!($dir =~ /(\\|\/)$/));
    $dir =~ s/\//\\/g;
    ${$rh}{'PROJECT_VERS'} = 1; # version of the HASH
    ${$rh}{'PROJECT_FILE'} = $nam.$ext# 2010/05/07 - was $fil
    ${$rh}{'PROJECT_FDIR'} = $dir;
    ${$rh}{'PROJECT_DSPF'} = $nam.".dsp";
    ${$rh}{'PROJECT_FLAG'} = 0;
    ${$rh}{'PROJECT_APTP'} = '';
    ${$rh}{'PROJECT_CCNT'} = 0; # count of configurations
    ${$rh}{'PROJECT_CFGS'} = [ ];   # no configs yet
    ${$rh}{'PROJECT_SRCS'} = [ ];   # no sources yet
    ${$rh}{'CURR_FLAG'}    = 0;
    ${$rh}{'CURR_LOFF'}    = 0; # last/current source OFFSET
    ${$rh}{'CURR_LINE'}    = '<not started>';
    return $rh;
}

my %ignore_in_ct_lh = ( 
    'AssemblerListingLocation' => 1,
    'EnableFunctionLevelLinking' => 2,
    'InlineFunctionExpansion' => 3,
    'ObjectFile' => 4,
    'Optimization' => 5,
    'PrecompiledHeaderFile' => 6,
    'ProgramDataBaseFileName' => 7,
    'RuntimeTypeInfo' => 8,
    'StringPooling' => 9,
    'SuppressStartupBanner' => 10,
    'WarningLevel' => 11,
    '<Tool' => 12,
    'Name' => 13,
    '/>' => 14,
    'BasicRuntimeChecks' => 14,
    'DebugInformationFormat' => 15,
    'MinimalRebuild' => 16
    );

sub get_item_from_hash($$) {
    my ($rh,$key) = @_;
    my ($item);
    if (defined ${$rh}{$key}) {
        $item = ${$rh}{$key};
    } else {
        prtw("ERROR:scanvc: Key [$key] NOT present in HASH!\n");
        pgm_exit(1,"ENSURE key [$key] ADDED TO HASH!\n");
    }
    return $item;
}

sub get_per_file_hash($) {
    my ($rh) = shift;
    return get_item_from_hash($rh,'CURR_PFHR');
}

sub get_last_src_offset($) {
    my ($rh) = shift;
    return get_item_from_hash($rh,'CURR_LOFF'); # last/current source OFFSET
}

sub get_current_xline_stg($) {
    my ($rh) = shift;
    return get_item_from_hash($rh,'CURR_LINE'); # = $xln
}

sub get_project_configs($) {
    my ($rh) = shift;
    return get_item_from_hash($rh,'PROJECT_CFGS');
}

sub svc_get_project_name_stg($) {
    my ($rh) = shift;
    return get_item_from_hash($rh,'PROJECT_NAME');
}

sub get_project_srcs_ref($) {
    my ($rh) = shift;
    return get_item_from_hash($rh,'PROJECT_SRCS');
}



sub add_vs_project_items($$$$) {
    my ($rh, $rah, $xln, $fil) = @_;
    my ($seek,$val1,$val2,$val3);
    $seek = 'Name';
    if (!defined ${$rah}{$seek} ) {
         mydie( "ERROR: 'VisualStudioProject' DOES NOT CONTAIN(14) a project NAME! NO GO!! ABORTING!!! [$fil]\n" );
    }
    $val1 = strip_quotes(${$rah}{$seek});   # get the (all important) PROJECT NAME
    $val2 = '';
    $val3 = '';
    $seek = 'ProjectType';
    if (defined ${$rah}{$seek}) {
        $val3 = strip_dotrel(strip_quotes(trim_all(${$rah}{$seek})));
    }
    $seek = 'Version';
    if (defined ${$rah}{$seek}) {
        $val2 = strip_dotrel(strip_quotes(trim_all(${$rah}{$seek})));
    }
    ${$rh}{'PROJECT_NAME'} = $val1; # SET the PROJECT NAME!
    ${$rh}{'PROJECT_MSCV'} = $val2;
    ${$rh}{'PROJECT_TYPE'} = $val3;
    prt( "[v01] $xln Bgn VisualStudioProject name=[$val1], type=[$val3], vers=[$val2]\n" ) if ($dbg_v01);
}

# extract_curr_items($rh,\$xln,\$rah,\$tag,\$pname,\$fil,\$projname,\$line,\$flag);
sub extract_curr_items($$$$$$$$$) {
    my ($rh,$rxln,$rrah,$rtag,$rpnm,$rfil,$rnam,$rlin,$rflg) = @_;
    ${$rxln} = ${$rh}{'CURR_LINE'};
    ${$rrah} = ${$rh}{'CURR_HASH'}; # Current REF HASH
    ${$rtag} = ${$rh}{'CURR_TAG'};
    ${$rpnm} = ${$rh}{'CURR_NAME'};
    ${$rlin} = ${$rh}{'CURR_TEXT'};
    ${$rfil} = ${$rh}{'PROJECT_FILE'};
    ${$rnam} = ${$rh}{'PROJECT_NAME'};
    ${$rflg} = ${$rh}{'CURR_FLAG'};
}

# Specifically interested in addeding
# $seek = 'OutputDirectory';
# $seek = 'IntermediateDirectory';
# %comspec% /k ""C:\Program Files\Microsoft Visual Studio 9.0\VC\vcvarsall.bat"" x86
# $(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops
my %missing_props = ();
sub svc_add_props_to_hash($$$$) {     # ( $adddeps, \%atthash );
    my ($fil,$fils,$rh,$props) = @_;
    my (@arr,$cnt,$i,$nm,$dir,$itm,$ff,%lnmap,$xlncnt,@lines,$lncnt,$lnnum);
    my ($line,$xln,@attribs,$ratthash,$key,$val);
    my ($val2, $tkey, $tag, $idir);
    my @parr = split(";",$props);
    ($nm,$dir) = fileparse($fil);
    $dir = strip_dotrel($dir);
    @arr = split(/[;,]/,$fils); # can be MORE THAN ONE property sheet
    $cnt = scalar @arr;
    prt( "[v26] Processing prop file(s) [$fils] cnt=$cnt\n" ) if ($dbg_v26);
    for ($i = 0; $i < $cnt; $i++) {
        $itm = strip_dotrel(trim_all(strip_quotes(trim_all($arr[$i]))));
        if ($itm =~ /^\$\(VCInstallDir\)/i) {
            $idir = '';
            if ( get_vs_install_dir(\$idir) && length($idir) ) {
                $itm =~ s/^\$\(VCInstallDir\)//i;
                $dir = $idir."\\VC";
                prt( "[v26] Setting dir to [$dir], for item [$itm]\n" ) if ($dbg_v26);
            } else {
                prtw("WARNING:scanvc: Failed to get VCINSTALLDIR!\n");
            }
        }
        # ===========================================================================
        $ff = $dir;
        $ff .= "\\" if ( length($dir) && !(($dir =~ /(\\|\/)$/)||($itm =~ /^(\\|\/)/)) );
        $ff .= $itm;
        ###prt( "Finding [$ff], from [$dir]/[$itm]...\n" );
        # ===========================================================================
        if (-f $ff) {
            prt( "[v26] Loading inherited props [$ff]..\n" ) if ($dbg_v26);
            if (open INF, "<$ff") {
                %lnmap = ();
                @lines = <INF>;
                close INF;
                $xlncnt = scalar @lines;
                @lines = svc_xml_to_lines(\%lnmap, \@lines);
                $lncnt = scalar @lines;
                $lnnum = 0;
                prt( "[v26] Processing file [$ff], $lncnt lines ($xlncnt) ...\n" ) if ($dbg_v26);
                foreach $line (@lines) {
                    $lnnum++;
                    $xln = $lnmap{$lnnum};
                    $ratthash = line_2_hash_on_equals($line,$lnnum);
                    $tag = $attribs[0];
                    foreach $key (sort keys %{$ratthash}) {
                        $val = ${$ratthash}{$key};
                        $tkey = substr($key,16);
                        if (length($val) && is_in_array($tkey,@parr)) {
                            if (defined ${$rh}{$tkey}) {
                                $val2 = ${$rh}{$tkey};
                                prtw( "WARNING:scanvc: key=[$tkey], value=[$val2] REPLACED with [$val] [$fil]\n" );
                            } else {
                                prt( "[v26] Added key=[$tkey], value=[$val]\n" ) if ($dbg_v26);
                                ${$rh}{$tkey} = $val;
                            }
                        }
                    }
                }
            } else {
                prtw( "WARNING:scanvc: FAILED to OPEN inherited props [$ff] [$fil]\n" );
            }
        } else {
            # 15/04/2012 - Downgrade this to a note only, and only once
            # prtw( "WARNING:scanvc: FAILED to FIND inherited props [$itm] [$ff]! in [$fil]\n" );
            if (!defined $missing_props{$ff}) {
                $missing_props{$ff} = 1;
                prt( "NOTE:scanvc: FAILED to FIND inherited props [$itm]\n[$ff]! in [$fil]\n" );
            }
        }
    }
}

sub add_vs_config_item($) {
    my ($rh) = @_;
    my ($xln,$rah,$tag,$pname,$fil,$projname,$line,$flag);
    my ($tmp);  # 2010/05/05 
    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);
    # 20120205 - Try to smooth this out, and accept 'Deb' or 'Rel'
    # 20120417 - Use one service for all in lib+dsphdrs.pl
    $tmp = get_act_config_type($conf);   # test /Release/i and /Debug/i and others

#    if ($conf =~ /Debug/i) {
#        $tmp = 1;
#    } elsif (($conf =~ /Release/i) || ($conf =~ /DLL/i)) {
#        # 2010/05/05 - assume 'DLL' means RELEASE without WARNING
#        $tmp = 0;
#    } elsif ($conf =~ /Rel/i) {
#        $tmp = 0;
#    } elsif ($conf =~ /Deb/i) {
#        $tmp = 1;
#    } else {
#        $tmp = 0;
#        prtw( "WARNING:vcscan:$xln: pname=[$conf] NOT Debug or Release - def to REL! [$fil]\n" );
#    }
    $dsp_sub_sub = get_default_sub3($tmp);
    my $rcfgs = get_project_configs($rh);   # 'PROJECT_CFGS'
    $tmp = ${$rh}{'PROJECT_CCNT'};
    $tmp++;
    prt("[v40] STORE:$tmp: In rcfgs (ra)[$confname], [$var1], [$conf], & \$dsp_sub_sub ] )\n") if ($dbg_v40); # ONLY STORE OF 'PROJECT_CFGS'
    push(@{$rcfgs}, [ $confname, $var1, $conf, $dsp_sub_sub ]); # ONLY STORE OF 'PROJECT_CFGS'
    ${$rh}{'PROJECT_CCNT'}++;   # count of stored 'PROJECT_CFGS
    ${$rh}{'CURR_DSUB'} = $dsp_sub_sub;
    #push(@configs,[ $pname, $var1, $conf ]);
    #  // This is an internal type to Visual Studio, it seems that:
    #  // 4 == static library
    #  // 2 == dll
    #  // 1 == executable - note, subsytem decides if this remains 'Application' or becomes 'Console Application'
    #  // 10 == utility
    $seek = 'ConfigurationType';
    if (defined ${$rah}{$seek}) {
        $tmp = trim_all(${$rah}{$seek});
        $tmp =~ s/>$//; # remove any trailing
        $adddeps = strip_quotes(trim_all($tmp));
        # $apptype = get_app_conf_type($adddeps);
        if (get_app_conf_type2($adddeps,\$apptype)) {
            # could be a ConfigurationType="0", which is a Makefile type project ;=(( NOT YET SUPPORTED
            $tmp = '';
            $tmp = "Appears to be a makefile type project! NOT YET USPPORTED!!!\n" if ($adddeps eq '0');
            pgm_exit(1,"ERROR: Failed to get_app_conf_type2 with value [$adddeps],\nline [$line]\n$xln file $fil\n$tmp");
        }
        $flag |= $cf_apptype# signal, we have an APP TYPE - VERY IMPORTANT
        if (length($dnapptype)) {
            if ($flag & $cf_apptyp2) {
                $apptype = $dnapptype;
            }
            if ($dnapptype ne $apptype) {
                prt( "[v41] $xln Project [$projname], APP_TYPE RESET per 'ConfigurationType' [$apptype] from [$dnapptype]...\n" ) if ($dbg_v41);
                $dnapptype = $apptype;
            }
        } else {
            prt( "[v41] $xln Project [$projname], APP_TYPE per 'ConfigurationType' [$apptype]...\n" ) if ($dbg_v41);
            $dnapptype = $apptype;
        }
        ${$rh}{'PROJECT_APTP'} = $dnapptype;
        ${$rh}{'CURR_FLAG'} = $flag;
    } else {
        prtw( "WARNING:scanvc:$xln: DOES NOT CONTAIN(8) 'ConfigurationType' [$line] [$fil]\n" );
    }
    # 2009/10/15 - handle better 'InheritedPropertySheets=".\vc9_lame_config.vsprops;.\arch_nasm.vsprops"'
    # and this PROPS (vsprops) MAY contain the following items
    $seek = 'InheritedPropertySheets';
    if (defined ${$rah}{$seek}) {
        $adddeps = strip_quotes(trim_all(${$rah}{$seek}));
        svc_add_props_to_hash( $fil, $adddeps, $rah, "OutputDirectory;IntermediateDirectory" );
    }
    $seek = 'OutputDirectory';
    if (defined ${$rah}{$seek}) {
        # 20090808 - improved to handle
        # EG: 9:18-24: Changed(1) OutputDirectory from ["Debug"]
        # to ["$(SolutionDir)$(ConfigurationName)"]
        #$adddeps = add_quotes(strip_dotrel(strip_quotes(trim_all($atthash{$seek}))));
        $adddeps = strip_dotrel(strip_quotes(trim_all(${$rah}{$seek})));
        $adddeps =~ s/\$\(SolutionDir\)//;
        $adddeps =~ s/\$\(ConfigurationName\)/$confname/;
        if ( ${$dsp_sub_sub}{$var1} ne add_quotes($adddeps)) {
            prt( "[v33] $xln Changed(1) [OutputDirectory] from [".${$dsp_sub_sub}{$var1}."] to [".add_quotes($adddeps)."]\n" ) if ($dbg_v33);
        }
        ${$dsp_sub_sub}{$var1} = add_quotes($adddeps);
    } else {
        prtw( "WARNING:scanvc:xln: DOES NOT CONTAIN(9) '$seek' [$line] [$fil]\n" );
    }
    $seek = 'IntermediateDirectory';
    if (defined ${$rah}{$seek}) {
        # 20090808 - improved to handle
        # 9:18-24: Changed(2) IntermediateDirectory from ["Debug"] 
        # to ["$(ConfigurationName)"]
        # $adddeps = add_quotes(strip_dotrel(strip_quotes(trim_all($atthash{$seek}))));
        $adddeps = strip_dotrel(strip_quotes(trim_all(${$rah}{$seek})));
        $adddeps =~ s/\$\(SolutionDir\)//;
        $adddeps =~ s/\$\(ConfigurationName\)/$confname/;
        if (${$dsp_sub_sub}{$var2} ne add_quotes($adddeps)) {
            prt( "[v20] $xln Changed(2) [IntermediateDirectory] from [".${$dsp_sub_sub}{$var2}."] to [".add_quotes($adddeps)."]\n" ) if ($dbg_v20);
        }
        $sc_last_intdir = $adddeps;
        ${$dsp_sub_sub}{$var2} = add_quotes($sc_last_intdir);
    } else {
        prtw( "WARNING:scanvc:$xln DOES NOT CONTAIN(10) '$seek' [$line] [$fil]\n" );
    }
    prt( "[v06] $xln Bgn ConfigurationName=[$confname] conf=[$conf] [$line] ...($tag)\n" ) if ($dbg_v06);
}

#    my %prj_key_info = (
#        'PROJECT_CFGS' => '<A> Configurations found',
#        'PROJECT_NAME' => '<S> Name of project:',
#        'PROJECT_CCNT' => '<N> Count of configs',
#        'PROJECT_FILE' => '<S> Input File',
#        'PROJECT_SRCS' => '<A> Array of sources',
#        'PROJECT_TYPE' => '<S> MSVS type',
#        'PROJECT_VERS' => '<N> HASH Version',
#        'PROJECT_MSCV' => '<S> MSVC Version',
#        'PROJECT_APTP' => '<S> Application Type',
#        'PROJECT_FLAG' => '<N> Project flag'
#    );
sub get_prj_key_info_ref() {
    my %prj_key_info = (
        'PROJECT_CFGS' => '<A> Configs found:    ',
        'PROJECT_NAME' => '<S> Name of project:  ',
        'PROJECT_CCNT' => '<N> Count of configs: ',
        'PROJECT_FILE' => '<S> Input File:       ',
        'PROJECT_FDIR' => '<S> Input Directory:  ',
        'PROJECT_DSPF' => '<S> Output File:      ',
        'PROJECT_SRCS' => '<A> Array of sources: ',
        'PROJECT_TYPE' => '<S> MSVS type:        ',
        'PROJECT_VERS' => '<N> HASH Version:     ',
        'PROJECT_MSCV' => '<S> MSVC Version:     ',
        'PROJECT_APTP' => '<S> Application Type: ',
        'PROJECT_FLAG' => '<N> Project flag:     '
    );
    return \%prj_key_info;
}

sub set_inc_hash($$) {
    my ($hr,$v2) = @_;
    my @tarr = space_split($v2);
    my $cnt = scalar @tarr;
    my ($i,$val,$i2);
    for ($i = 0; $i < $cnt; $i++) {
        $val = $tarr[$i];
        $i2 = $i + 1;
        if (($val =~ /^\/I/)&&($i2 < $cnt)) {
            $i++;
            $val = strip_quotes($tarr[$i]);
            ${$hr}{$val} = 1;
        }
    }
}

sub set_def_hash($$) {
    my ($hr,$v2) = @_;
    my @tarr = space_split($v2);
    my $cnt = scalar @tarr;
    my ($i,$val,$i2);
    for ($i = 0; $i < $cnt; $i++) {
        $val = $tarr[$i];
        $i2 = $i + 1;
        if (($val =~ /^\/D/)&&($i2 < $cnt)) {
            $i++;
            $val = strip_quotes($tarr[$i]);
            ${$hr}{$val} = 1;
        }
    }
}


#sub show_new_hash_ref($) {
sub show_hash_results3($) {
    my ($nhr) = @_;
    my @arr = keys( %{$nhr} );
    my $cnt = scalar @arr;
    my ($key,$name,$val,$inf,$acnt,$src);
    my ($grp,$flt,$min1,$min2,$len);
    my ($i,$i2,$msg,$rsb,$scnt,@karr);
    my ($ky,$v2,$sdir,$ff,$ok,$type);
    $key = 'PROJECT_NAME';
    $name = ${$nhr}{$key};
    $key = 'PROJECT_FDIR';
    $sdir = ${$nhr}{$key};
    $key = 'PROJECT_APTP';
    $type = ${$nhr}{$key};
    prt( "Show of NEW hash ref., up to $cnt keys... project [$name]\n" );
    $cnt = 0;
    my $rpki = get_prj_key_info_ref();
    my @c_files = ();
    my @h_files = ();
    my @o_files = ();
    my %inc_hash = ();
    my %def_hash = ();
    foreach $key (@arr) {
        $val = ${$nhr}{$key};
        next if ($key =~ /^TEMP_/);
        if ( $key =~ /^CURR_/ ) {
            # ignore these CURRENT state items
        } else {
            $cnt++;
            if (defined ${$rpki}{$key}) {
                $inf = ${$rpki}{$key};
                if (($inf =~ /^<S>/)||($inf =~ /^<N>/)) {
                    prt( "$key $inf =[$val]\n" );
                } else {
                    $acnt = scalar @{$val};
                    prt( "$key $inf =(ARRAY of count $acnt)\n" );
                    if ($key eq 'PROJECT_SRCS') {
                        $min1 = 0;
                        $min2 = 0;
                        for ($i = 0; $i < $acnt; $i++) {
                            $src = ${$val}[$i][0];
                            $grp = ${$val}[$i][1];
                            $flt = ${$val}[$i][2];
                            $len = length($src);
                            $min1 = $len if ($len > $min1);
                            $len = length($grp);
                            $min2 = $len if ($len > $min2);
                        }
                        for ($i = 0; $i < $acnt; $i++) {
                            $i2 = $i + 1;
                            $src = ${$val}[$i][0];
                            $grp = ${$val}[$i][1];
                            $flt = ${$val}[$i][2];
                            if ($src =~ /^\w{1}:(\\|\/)/) { # this appears to be a FULL FILE NAME like C:
                                $ff = $src;
                            } else {
                                $ff = fix_rel_path3($sdir.$src,'show_hash_results3'); # in fgutils02.pl
                            }
                            $ok = (-f $ff) ? 'ok' : 'NF';
                            if (is_c_source_extended($src)) {
                                push(@c_files,$src);
                            } elsif (is_h_source($src)) {
                                push(@h_files,$src);
                            } else {
                                push(@o_files,$src);
                            }
                            # setup for display
                            $src .= ' ' while(length($src) < $min1);
                            $grp .= ' ' while(length($grp) < $min2);
                            $msg = sprintf("%3d:",$i2);
                            prt( "$msg $src $grp $flt $ok\n" );
                        }
                    } elsif ($key eq 'PROJECT_CFGS') {
                        # my $rcfgs = ${$rh}{'PROJECT_CFGS'};
                        #                   0       1      2      3
                        # push(@{$rcfgs}, [ $pname, $var1, $conf, $dsp_sub_sub ]);
                        for ($i = 0; $i < $acnt; $i++) {
                            $i2 = $i + 1;
                            $src = ${$val}[$i][0];
                            $grp = ${$val}[$i][1];
                            $flt = ${$val}[$i][2];
                            $rsb = ${$val}[$i][3];
                            @karr = keys(%{$rsb});
                            $scnt = scalar @karr;

                            $msg = sprintf("%3d:",$i2);
                            prt( "$msg $src $grp $flt $scnt\n" );
                            foreach $ky (@karr) {
                                $v2 = ${$rsb}{$ky};
                                prt( $ky = [$v2]\n" );
                                if ($ky eq '-NEW_INCS-') {
                                    set_inc_hash(\%inc_hash,$v2);
                                } elsif ($ky eq '-NEW_DEFS-') {
                                    set_def_hash(\%def_hash,$v2);
                                }
                            }
                        }
                    }
                }
            } else {
                # But NOT sure WHY this warnings
                # see # FIX20120718 - some 'fixes' if NOT already defined in vcpro05.pl
                if ($key eq 'PROJECT_AM_FILE') {
                    # 20140103 - no warning for this
                } elsif ($key eq 'PROJECT_ROOT') {
                    # 20140103 - no warning for this
                } else {
                    prtw( "WARNING:scanvc: [$key] NOT IN INFO LIST, so do not know type! see sub get_prj_key_info_ref() & \%prj_key_info\n" );
                }
            }
        }
    }
    prt("Done show of $cnt keys... project [$name]\n");
    my %hash = ();
    $hash{'PROJECT_C_SOURCES'} = \@c_files;
    $hash{'PROJECT_H_SOURCES'} = \@h_files;
    $hash{'PROJECT_O_SOURCES'} = \@o_files;
    $hash{'PROJECT_NAME'} = $name;
    $hash{'PROJECT_SDIR'} = $sdir;
    $hash{'PROJECT_TYPE'} = $type;
    $hash{'PROJECT_INCS'} = \%inc_hash;
    $hash{'PROJECT_DEFS'} = \%def_hash;
    return \%hash;
}

# Selective SHOW of HASH
# Show of NEW hash ref., up to 27 keys... project [gennmtab]
our $sh_vers = 0x01;    # PROJECT_MSCV <S> MSVC Version:      =[8.00]
our $sh_cfgs = 0x02;    # PROJECT_CFGS <A> Configs found:     =(ARRAY of count 2)
our $sh_odir = 0x04;    #   1: Debug -NEW_OUTD- Debug|Win32 8 and -NEW_OUTD- = ["Debug\gennmtab"]
our $sh_intr = 0x08;    #   -NEW_INTER- = ["Debug\gennmtab"]
our $sh_incs = 0x010;    #   -NEW_INCS- = [/I ".."]
our $sh_libs = 0x020;    #   -NEW_LIBS- = [odbc32.lib odbccp32.lib]
our $sh_out  = 0x040;    #   -NEW_OUT- = [/out:bin\gennmtabD.exe]
our $sh_post = 0x080;    #   -NEW_POST- = [# Begin Special Build Tool
    # SOURCE="$(InputPath)"
    # PostBuild_Desc="(D) Generating nametab.h ..."
    # PostBuild_Cmds=bin\gennmtabD.exe >..\lib\expat\xmltok\nametab.h
    # End Special Build Tool]
our $sh_rt   = 0x0100;   #   -NEW_RT- = [/MTd]
our $sh_defs = 0x0200;   #  -NEW_DEFS- = [/D "WIN32" /D "_DEBUG" /D "_CONSOLE"]
our $sh_cfg_items = ($sh_odir | $sh_intr | $sh_incs | $sh_libs | $sh_out | $sh_post | $sh_rt | $sh_defs);
#  2: Release -NEW_OUTD- Release|Win32 8
#  -NEW_OUTD- = ["Release\gennmtab"]
#  -NEW_INTER- = ["Release\gennmtab"]
#  -NEW_INCS- = [/I ".."]
#  -NEW_LIBS- = [odbc32.lib odbccp32.lib]
#  -NEW_OUT- = [/out:bin\gennmtab.exe]
#  -NEW_POST- = [# Begin Special Build Tool
#SOURCE="$(InputPath)"
#PostBuild_Desc="(R) Generating nametab.h ..."
#PostBuild_Cmds=bin\gennmtab.exe >..\lib\expat\xmltok\nametab.h
# End Special Build Tool
#]
#  -NEW_RT- = [/MT]
#  -NEW_DEFS- = [/D "WIN32" /D "NDEBUG" /D "_CONSOLE"]
our $sh_proj = 0x0400;   # PROJECT_NAME <S> Name of project:   =[gennmtab]
our $sh_ccnt = 0x0800;   # PROJECT_CCNT <N> Count of configs:  =[2]
our $sh_fdir = 0x01000;  # PROJECT_FDIR <S> Input Directory:   =[C:\FG\FGCOMXML\xmlrpc-c\Windows\]
our $sh_inpf = 0x02000;  # PROJECT_FILE <S> Input File:        =[gennmtab.vcproj]
our $sh_srcs = 0x04000;  # PROJECT_SRCS <A> Array of sources:  =(ARRAY of count 1)
#  1: ..\lib\expat\gennmtab\gennmtab.c Source Files cpp;c;cxx;rc;def;r;od
our $sh_ptyp = 0x08000;  # PROJECT_TYPE <S> MSVS type:         =[Visual C++]
our $sh_dspf = 0x010000; # PROJECT_DSPF <S> Output File:       =[gennmtab.dsp]
our $sh_hash = 0x020000; # PROJECT_VERS <N> HASH Version:      =[1]
our $sh_atyp = 0x040000; # PROJECT_APTP <S> Application Type:  =[Console Application]
our $sh_pflg = 0x080000; # PROJECT_FLAG <N> Project flag:      =[0]
# Done show of 12 keys... project [gennmtab]
sub get_show_value($) {
    my $msg = shift;
    my $show = 0;
    my @arr = split(/;+/,$msg);
    my ($tmp);
    my %hash = ();
    foreach $tmp (@arr) {
        next if (length($tmp) == 0);
        $hash{$tmp} = 1;
    }
    $show |= $sh_vers if (defined $hash{'vers'});  # PROJECT_MSCV <S> MSVC Version:      =[8.00]
    $show |= $sh_cfgs if (defined $hash{'cfgs'});  # PROJECT_CFGS <A> Configs found:     =(ARRAY of count 2)
    $show |= $sh_odir if (defined $hash{'odir'});  #   1: Debug -NEW_OUTD- Debug|Win32 8 and -NEW_OUTD- = ["Debug\gennmtab"]
    $show |= $sh_intr if (defined $hash{'inte'});  #   -NEW_INTER- = ["Debug\gennmtab"]
    $show |= $sh_incs if (defined $hash{'incs'});  #   -NEW_INCS- = [/I ".."]
    $show |= $sh_libs if (defined $hash{'libs'});  #   -NEW_LIBS- = [odbc32.lib odbccp32.lib]
    $show |= $sh_out  if (defined $hash{'out'} );  #   -NEW_OUT- = [/out:bin\gennmtabD.exe]
    $show |= $sh_post if (defined $hash{'post'});  #   -NEW_POST- = [# Begin Special Build Tool
    $show |= $sh_rt   if (defined $hash{'rt'}  );  #   -NEW_RT- = [/MTd]
    $show |= $sh_defs if (defined $hash{'defs'});  #  -NEW_DEFS- = [/D "WIN32" /D "_DEBUG" /D "_CONSOLE"]
    $show |= $sh_proj if (defined $hash{'proj'});  # PROJECT_NAME <S> Name of project:   =[gennmtab]
    $show |= $sh_ccnt if (defined $hash{'ccnt'});  # PROJECT_CCNT <N> Count of configs:  =[2]
    $show |= $sh_fdir if (defined $hash{'fdir'});  # PROJECT_FDIR <S> Input Directory:   =[C:\FG\FGCOMXML\xmlrpc-c\Windows\]
    $show |= $sh_inpf if (defined $hash{'inpf'});  # PROJECT_FILE <S> Input File:        =[gennmtab.vcproj]
    $show |= $sh_srcs if (defined $hash{'srcs'});  # PROJECT_SRCS <A> Array of sources:  =(ARRAY of count 1)
    $show |= $sh_ptyp if (defined $hash{'ptyp'});  # PROJECT_TYPE <S> MSVS type:         =[Visual C++]
    $show |= $sh_dspf if (defined $hash{'dspf'});  # PROJECT_DSPF <S> Output File:       =[gennmtab.dsp]
    $show |= $sh_hash if (defined $hash{'hash'});  # PROJECT_VERS <N> HASH Version:      =[1]
    $show |= $sh_atyp if (defined $hash{'atyp'});  # PROJECT_APTP <S> Application Type:  =[Console Application]
    $show |= $sh_pflg if (defined $hash{'pflg'});  # PROJECT_FLAG <N> Project flag:      =[0]
    return $show;
}

sub get_show_list($) {
    my $show = shift;
    my $msg = '';
    $msg .= ';vers' if ($show & $sh_vers);    # PROJECT_MSCV <S> MSVC Version:      =[8.00]
    $msg .= ';cfgs' if ($show & $sh_cfgs);    # PROJECT_CFGS <A> Configs found:     =(ARRAY of count 2)
    $msg .= ';odir' if ($show & $sh_odir);    #   1: Debug -NEW_OUTD- Debug|Win32 8 and -NEW_OUTD- = ["Debug\gennmtab"]
    $msg .= ';inte' if ($show & $sh_intr);    #   -NEW_INTER- = ["Debug\gennmtab"]
    $msg .= ';incs' if ($show & $sh_incs);    #   -NEW_INCS- = [/I ".."]
    $msg .= ';libs' if ($show & $sh_libs);    #   -NEW_LIBS- = [odbc32.lib odbccp32.lib]
    $msg .= ';out'  if ($show & $sh_out );    #   -NEW_OUT- = [/out:bin\gennmtabD.exe]
    $msg .= ';post' if ($show & $sh_post);    #   -NEW_POST- = [# Begin Special Build Tool
    $msg .= ';rt'   if ($show & $sh_rt  );   #   -NEW_RT- = [/MTd]
    $msg .= ';defs' if ($show & $sh_defs);   #  -NEW_DEFS- = [/D "WIN32" /D "_DEBUG" /D "_CONSOLE"]
    $msg .= ';proj' if ($show & $sh_proj);   # PROJECT_NAME <S> Name of project:   =[gennmtab]
    $msg .= ';ccnt' if ($show & $sh_ccnt);   # PROJECT_CCNT <N> Count of configs:  =[2]
    $msg .= ';fdir' if ($show & $sh_fdir);  # PROJECT_FDIR <S> Input Directory:   =[C:\FG\FGCOMXML\xmlrpc-c\Windows\]
    $msg .= ';inpf' if ($show & $sh_inpf);  # PROJECT_FILE <S> Input File:        =[gennmtab.vcproj]
    $msg .= ';srcs' if ($show & $sh_srcs);  # PROJECT_SRCS <A> Array of sources:  =(ARRAY of count 1)
    $msg .= ';ptyp' if ($show & $sh_ptyp);  # PROJECT_TYPE <S> MSVS type:         =[Visual C++]
    $msg .= ';dspf' if ($show & $sh_dspf); # PROJECT_DSPF <S> Output File:       =[gennmtab.dsp]
    $msg .= ';hash' if ($show & $sh_hash); # PROJECT_VERS <N> HASH Version:      =[1]
    $msg .= ';atyp' if ($show & $sh_atyp); # PROJECT_APTP <S> Application Type:  =[Console Application]
    $msg .= ';pflg' if ($show & $sh_pflg); # PROJECT_FLAG <N> Project flag:      =[0]
    $msg =~ s/^;//;
    return $msg;
}

sub show_hash_results4($$) {
    my ($nhr,$show) = @_;
    my @arr = keys( %{$nhr} );
    my $cnt = scalar @arr;
    my ($key,$name,$val,$inf,$acnt,$src);
    my ($grp,$flt,$min1,$min2,$len);
    my ($i,$i2,$msg,$rsb,$scnt,@karr);
    my ($ky,$v2,$sdir,$ff,$ok,$sflag,$shwn);
    $key = 'PROJECT_NAME';
    $name = ${$nhr}{$key};
    $key = 'PROJECT_FDIR';
    $sdir = ${$nhr}{$key};
    $inf = ${$nhr}{'PROJECT_APTP'};
    $msg = get_show_list($show);
    if (length($msg) == 0) {
        prt("Project [$name] $inf - Nothing to SHOW of $cnt keys...\n");
        return;
    }
    prt("Project [$name] $inf - show [$msg], of $cnt keys...\n");
    $cnt = 0;
    my $rpki = get_prj_key_info_ref();
    $shwn = 0;
    foreach $key (@arr) {
        $val = ${$nhr}{$key};
        next if ($key =~ /^TEMP_/); # IGNORE 'TEMP_*' items
        if ( $key =~ /^CURR_/ ) {
            # ignore these CURRENT state items
        } else {
            $cnt++;
            if (defined ${$rpki}{$key}) {
                $inf = ${$rpki}{$key};
                $sflag = 0;
                if (($inf =~ /^<S>/)||($inf =~ /^<N>/)) {
                    if ($key eq 'PROJECT_MSCV') {
                        $sflag = 1 if ($show & $sh_vers);
                    } elsif ($key eq 'PROJECT_NAME') {
                        $sflag = 1 if ($show & $sh_proj);
                    } elsif ($key eq 'PROJECT_CCNT') {
                        $sflag = 1 if ($show & $sh_ccnt);
                    } elsif ($key eq 'PROJECT_FDIR') {
                        $sflag = 1 if ($show & $sh_fdir);
                    } elsif ($key eq 'PROJECT_FILE') {
                        $sflag = 1 if ($show & $sh_inpf);
                    } elsif ($key eq 'PROJECT_TYPE') {
                        $sflag = 1 if ($show & $sh_ptyp);
                    } elsif ($key eq 'PROJECT_DSPF') {
                        $sflag = 1 if ($show & $sh_dspf);
                    } elsif ($key eq 'PROJECT_VERS') {
                        $sflag = 1 if ($show & $sh_hash);
                    } elsif ($key eq 'PROJECT_APTP') {
                        $sflag = 1 if ($show & $sh_atyp);
                    } elsif ($key eq 'PROJECT_FLAG') {
                        $sflag = 1 if ($show & $sh_pflg);
                    } else {
                        $sflag = 1;
                        prtw("WARNING: lib_vcscan:show_hash_results4: has value $key not cased!\n");
                    }
                    if ($sflag) {
                        prt( "$key $inf =[$val]\n" );
                        $shwn++;
                    }
                } else {
                    $acnt = scalar @{$val};
                    if (($key eq 'PROJECT_SRCS')&&($show & $sh_srcs)) {
                        $grp = '';
                        if ($acnt) {
                            $src = ${$val}[0];
                            $grp = "(dep ".(scalar @{$src}).")";
                        }
                        prt( "$key $inf =(ARRAY of count $acnt) $grp\n" );
                        $min1 = 0;
                        $min2 = 0;
                        for ($i = 0; $i < $acnt; $i++) {
                            $src = ${$val}[$i][0];
                            $grp = ${$val}[$i][1];
                            $flt = ${$val}[$i][2];
                            $len = length($src);
                            $min1 = $len if ($len > $min1);
                            $len = length($grp);
                            $min2 = $len if ($len > $min2);
                        }
                        for ($i = 0; $i < $acnt; $i++) {
                            $i2 = $i + 1;
                            $src = ${$val}[$i][0];
                            $grp = ${$val}[$i][1];
                            $flt = ${$val}[$i][2];
                            $ff = fix_rel_path3($sdir.$src,'show_hash_results3'); # in fgutils02.pl
                            $ok = (-f $ff) ? 'ok' : 'NF';
                            $src .= ' ' while(length($src) < $min1);
                            $grp .= ' ' while(length($grp) < $min2);
                            $msg = sprintf("%3d:",$i2);
                            prt( "$msg $src $grp $flt $ok\n" );
                        }
                        $shwn++;
                    } elsif (($key eq 'PROJECT_CFGS')&&(($show & $sh_cfgs)||($show & $sh_cfg_items))) {
                        prt( "$key $inf =(ARRAY of count $acnt)\n" );
                        # my $rcfgs = ${$rh}{'PROJECT_CFGS'};
                        #                   0       1      2      3
                        # push(@{$rcfgs}, [ $pname, $var1, $conf, $dsp_sub_sub ]);
                        for ($i = 0; $i < $acnt; $i++) {
                            $i2 = $i + 1;
                            $src = ${$val}[$i][0];
                            $grp = ${$val}[$i][1];
                            $flt = ${$val}[$i][2];
                            $rsb = ${$val}[$i][3];
                            @karr = keys(%{$rsb});
                            $scnt = scalar @karr;
                            $msg = sprintf("%3d:",$i2);
                            #prt( "$msg $src $grp $flt $scnt\n" );
                            prt( "$msg $src $flt $scnt\n" );
                            foreach $ky (@karr) {
                                $v2 = ${$rsb}{$ky};
                                $sflag = 0;
                                if ($ky eq '-NEW_OUTD-') {
                                    $sflag = 1 if ($show & $sh_odir);
                                } elsif ($ky eq '-NEW_INTER-') {
                                    $sflag = 1 if ($show & $sh_intr);
                                } elsif ($ky eq '-NEW_INCS-') {
                                    $sflag = 1 if ($show & $sh_incs);
                                } elsif ($ky eq '-NEW_LIBS-') {
                                    $sflag = 1 if ($show & $sh_libs);
                                } elsif ($ky eq '-NEW_OUT-') {
                                    $sflag = 1 if ($show & $sh_out);
                                } elsif ($ky eq '-NEW_POST-') {
                                    $sflag = 1 if ($show & $sh_post);
                                } elsif ($ky eq '-NEW_RT-') {
                                    $sflag = 1 if ($show & $sh_rt);
                                } elsif ($ky eq '-NEW_DEFS-') {
                                    $sflag = 1 if ($show & $sh_defs);
                                } else {
                                    $sflag = 1;
                                    prtw("WARNING: lib_vcscan:show_hash_results4: has value $ky not cased!\n");
                                }
                                if ($sflag) {
                                    $shwn++;
                                    prt( $ky = [$v2]\n" );
                                }
                            }
                        }
                    }
                }
            } else {
                prtw( "WARNING:scanvc: [$key] NOT IN INFO LIST, so do not know type! see sub get_prj_key_info_ref() & \%prj_key_info\n" );
            }
        }
    }
    $inf = ${$nhr}{'PROJECT_APTP'};
    prt("Project [$name] $inf - Done $shwn of $cnt keys.\n");
}

sub adjust_inter_out_dirs($) {
    my ($nhr) = @_;
    my ($key1,$name,$key2,$cfgs,$ccnt,$i);
    $key1 = 'PROJECT_NAME';
    $key2 = 'PROJECT_CFGS';
    if (!defined ${$nhr}{$key1} || !defined ${$nhr}{$key2}) {
        prtw("WARNING: Hash does not contain $key1 or $key2! Can NOT adjust inter dirs!\n");
        return 0;
    }
    $name = ${$nhr}{$key1};
    $cfgs = ${$nhr}{$key2};
    $ccnt = scalar @{$cfgs};
    my ($cfgt,$fcfg,$rcfgs,$nout);
    $key1 = '-NEW_OUTD-';
    $key2 = '-NEW_INTER-';
    for ($i = 0; $i < $ccnt; $i++) {
        $cfgt = ${$cfgs}[$i][0];
        # $tmp = ${$cfgs}[$i][1];
        $fcfg = ${$cfgs}[$i][2];
        $rcfgs = ${$cfgs}[$i][3];
        # NOTE: HAVE TO USE FORWARD SLASH to avoid regex problem later
        if ($cfgt =~ /Debug/i) {
            $nout = "\"Debug/$name\"";
        } else {
            $nout = "\"Release/$name\"";
        }
        ${$rcfgs}{$key1} = $nout;
        ${$rcfgs}{$key2} = $nout;
    }
}

sub adjust_runtime_to($$) {
    my ($nhr,$rt) = @_;
    my ($key1,$name,$cfgs,$ccnt,$i);
    $key1 = 'PROJECT_CFGS';
    if ( !defined ${$nhr}{$key1} ) {
        prtw("WARNING: Hash does not contain $key1! Can NOT adjust RUNTIME to [$rt]!\n");
        return 0;
    }
    $cfgs = ${$nhr}{$key1};
    $ccnt = scalar @{$cfgs};
    my ($cfgt,$fcfg,$rcfgs,$nout);
    $key1 = '-NEW_RT-';
    for ($i = 0; $i < $ccnt; $i++) {
        $cfgt = ${$cfgs}[$i][0];
        # $tmp = ${$cfgs}[$i][1];
        $fcfg = ${$cfgs}[$i][2];
        $rcfgs = ${$cfgs}[$i][3];
        $nout = "/M".$rt;
        if ($cfgt =~ /Debug/i) {
            $nout .= 'd';
        }
        ${$rcfgs}{$key1} = $nout;
    }
}

# 'CA' => $app_console_stg,
# 'WA' => $app_windows_stg,
# 'DLL' => $app_dynalib_stg,
# 'SL' => $app_statlib_stg
sub adjust_output_name($) {
    my ($nhr) = @_;
    my ($key1,$name,$key2,$key3,$cfgs,$ccnt,$i,$val,$ext,$aptp);
    my $dir = '';
    $key1 = 'PROJECT_NAME';
    $key2 = 'PROJECT_CFGS';
    $key3 = 'PROJECT_APTP';
    if ( !defined ${$nhr}{$key1} || !defined ${$nhr}{$key2} || !defined ${$nhr}{$key3} ) {
        prtw("WARNING: Hash does not contain $key1, $key2 or $key3! Can NOT adjust OUTPUT -NEW_OUT-!\n");
        return 0;
    }
    $name = ${$nhr}{$key1};
    $cfgs = ${$nhr}{$key2};
    $aptp = ${$nhr}{$key3};
    $ccnt = scalar @{$cfgs};
    my ($cfgt,$fcfg,$rcfgs,$nout);
    my $rhs = get_app_type_hash_ref_short();
    foreach $key2 ( keys %{$rhs} ) {
        $val = ${$rhs}{$key2};
        if ($val eq $aptp) {
            # found the application type
            if ($key2 eq 'SL') {
                $dir = 'lib';
                $ext = '.lib';
            } elsif ($key2 eq 'DLL') {
                $dir = 'lib';
                $ext = '.dll';
            } else {
                $dir = 'bin';
                $ext = '.exe';
            }
            last;
        }
    }
    if (length($dir) == 0) {
        prtw("WARNING: Did not find [$aptp] in hash! Can NOT auto-set output! -NEW_OUT-!\n");
        return 0;
    }
    $key1 = '-NEW_OUT-';
    my $ret  = 0;
    for ($i = 0; $i < $ccnt; $i++) {
        $cfgt = ${$cfgs}[$i][0];
        # $tmp = ${$cfgs}[$i][1];
        $fcfg = ${$cfgs}[$i][2];
        $rcfgs = ${$cfgs}[$i][3];
        # NOTE: HAVE TO USE FORWARD SLASH to avoid regex problem later
        $nout = "/out:$dir\\$name";
        if ($cfgt =~ /Debug/i) {
            $nout .= "D";
        }
        $nout .= $ext;
        ${$rcfgs}{$key1} = $nout;
        $ret++;
    }
    return $ret;
}

# remove like -NEW_LIBS- = [wsock32.lib comctl32.lib /libpath:"..\lib" /nodefaultlib:"libcmtd"]
sub delete_nodefaultlib_all($$) {
    my ($nhr,$rdels) = @_;
    my ($key1,$name,$cfgs,$ccnt,$i);
    $key1 = 'PROJECT_CFGS';
    if ( !defined ${$nhr}{$key1} ) {
        prtw("WARNING: Hash does not contain $key1! Can NOT adjust /nodefaultlib:\"*...\"!\n");
        return 0;
    }
    $cfgs = ${$nhr}{$key1};
    $ccnt = scalar @{$cfgs};
    my ($cfgt,$fcfg,$rcfgs,$nout,@arr,$val,$lib);
    $key1 = '-NEW_LIBS-';
    for ($i = 0; $i < $ccnt; $i++) {
        $cfgt = ${$cfgs}[$i][0];
        # $tmp = ${$cfgs}[$i][1];
        $fcfg = ${$cfgs}[$i][2];
        $rcfgs = ${$cfgs}[$i][3];
        if (defined ${$rcfgs}{$key1}) {
            $nout = ${$rcfgs}{$key1};
            @arr = space_split($nout);
            $nout = '';
            foreach $val (@arr) {
                if ($val =~ /^\/nodefaultlib:\"(.+)\"$/) {
                    $lib = $1;
                    ${$rdels} .= ' ' if (length(${$rdels}));
                    ${$rdels} .= $lib;
                } else {
                    $nout .= ' ' if (length($nout));
                    $nout .= $val;
                }
            }
            ${$rcfgs}{$key1} = $nout if (length(${$rdels}));
        } else {
            # why no -NEW_LIBS- entry
            prtw("WARNING: Config [$fcfg] does NOT contain '$key1'!\n");
        }
    }
}

# seems MSVC8, and maybe others, when converting the MSVC6 DSP
# to a VCPROJ file can NOT tollerate a command
# ending in a '\' character, without quotes around it
# 20120128 - version 10 vcproj files, and maybe others, can have '&gt;' instead of '>'
# #########################################################
sub massage_command3($) {
    my ($txt) = shift;
    if ($txt =~ /\\$/) {
        my ($len, $ch, $bgn, $end);
        # need to back up to previous space,
        # and add quotes around the last command
        $len = length($txt);
        while ($len) {
            $len--;
            $ch = substr($txt,$len,1);
            if ($ch eq ' ') {
                last;
            }
        }
        if ($len) {
            $len++;
            $bgn = substr($txt,0,$len);
            $end = substr($txt,$len);
            $txt = $bgn.add_quotes($end);
        }
    }
    $txt =~ s/&gt;/>/g; # 20120128 - convert '&gt;' to '>'
    return $txt;
}

sub get_line_hash_missed($$$) {
    my ($rah,$dnsks,$ign) = @_;
    my @arr1 = split(/\|/,$dnsks);
    my @arr2 = sort(keys(%{$rah}));
    my $missed = '';
    my ($kitm,$ditm,,$fnd);
    foreach $kitm (@arr2) {  # process the keys
        if ( !defined ${$ign}{$kitm} ) {
            $fnd = 0;
            foreach $ditm (@arr1) {
                if ($kitm eq $ditm) {
                    $fnd = 1;
                    last;
                }
            }
            if (!$fnd) {
                $missed .= '|' if (length($missed));
                $missed .= $kitm;
            }
        }
    }
    #prtw( "WARNING:scanvc: MISSED [$missed]!\n" ) if (length($missed));
    return $missed;
}

sub get_ct_line_hash_missed($$) {
    my ($rah,$dnsks) = @_;
    return get_line_hash_missed($rah,$dnsks,\%ignore_in_ct_lh);
}

sub get_nodeflib_string($) {
    my ($add) = @_;
    my $rstg = '';
    if (length($add)) {
        $rstg = "/nodefaultlib:\"$add\"";
    }
    return $rstg;
}

my %not_handled = ();

sub process_vc_conf_tool_tag($) {
    my ($rh) = @_;
    my ($xln,$rah,$tag,$pname,$fil,$projname,$line,$flag);
    extract_curr_items($rh,\$xln,\$rah,\$tag,\$pname,\$fil,\$projname,\$line,\$flag);
    my ($var1,$var2,$var3,$seek);
    my ($ppdefs,$curval,$newval);
    my ($adddeps,$doneseeks,$missed);
    my ($tmp);  # 2010/05/01 
    my $last_src = ${$rh}{'CURR_LSRC'};
    my $last_nm  = ${$rh}{'CURR_LNME'};
    my $last_dir = ${$rh}{'CURR_LDIR'};
    my $last_ext = ${$rh}{'CURR_LEXT'};
    my $confname = ${$rh}{'CURR_CONF'};
    my $dsp_sub_sub = ${$rh}{'CURR_DSUB'};
    my $dnapptype = ${$rh}{'PROJECT_APTP'};
    my $lhlen = scalar keys(%{$rah});   # get item count in line hash
    my ($apptype,$outfile);

    $doneseeks = '';
    $outfile = '';
    if ($pname eq 'VCCLCompilerTool') {
        $var1 = '-NEW_INCS-';
        $var2 = '-NEW_DEFS-';
        $var3 = '-NEW_RT-';
        # '<Tool';
        # Name="VCCLCompilerTool"
        # Optimization="0"
        # AdditionalIncludeDirectories="../lib,../lib/curl_transport,...
        # PreprocessorDefinitions="_DEBUG;WIN32;_LIB;ABYSS_WIN32;CURL_STATICLIB" 
        # MinimalRebuild="true" 
        # BasicRuntimeChecks="3" 
        # RuntimeLibrary="1" 
        # PrecompiledHeaderFile=".\Debug\xmlrpccpp/xmlrpccpp.pch" 
        # AssemblerListingLocation=".\Debug\xmlrpccpp/" 
        # ObjectFile=".\Debug\xmlrpccpp/" 
        # ProgramDataBaseFileName=".\Debug\xmlrpccpp/" 
        # WarningLevel="3" 
        # SuppressStartupBanner="true" 
        # DebugInformationFormat="4" />]
        # WATCHOUT FOR 
        # AdditionalIncludeDirectories="..\..;&quot;..\..\..\zlib-1.2.3&quot;"
        
        $seek = 'AdditionalIncludeDirectories'; # -NEW_INCS_[DBG|REL]-
        $doneseeks = $seek;
        if ( defined ${$rah}{$seek} ) {
            $ppdefs = strip_quotes(trim_all(${$rah}{$seek}));
            $ppdefs =~ s/&amp;/&/g;     # 20081205 - added
            $ppdefs =~ s/&quot;/"/g;
            $curval = '';
            if (defined ${$dsp_sub_sub}{$var1}) {
               $curval = ${$dsp_sub_sub}{$var1};
            }
            $newval = get_includes_string($ppdefs);
            if ($curval ne $newval) {
               ${$dsp_sub_sub}{$var1} = $newval;
               if ($dbg_v25) {
                   prt( "[v25] " );
                  if (length($curval)) {
                     prt( "$xln VCCLCompilerTool:AdditionalIncludeDirectories: RESET [$var1] to [$newval] from [$curval]\n" );
                  } else {
                     prt( "$xln VCCLCompilerTool:AdditionalIncludeDirectories: set [$var1] to [$newval]\n" );
                  }
               }
            }
        } else { 
            ${$dsp_sub_sub}{$var1} = '';
            prt( "[v13] $xln 'VCCLCompilerTool' DOES NOT CONTAIN(1) 'AdditionalIncludeDirectories' [$line]\n" ) if ($dbg_v13);
        }

        $seek = 'PreprocessorDefinitions';
        $doneseeks .= "|$seek";
        if ( defined ${$rah}{$seek} ) {
            $ppdefs = strip_quotes(trim_all(${$rah}{$seek}));
            prt( "[v03] seek=PreprocessorDefinitions = [$ppdefs] [$fil]\n" ) if ($dbg_v03);
            $curval = '';
            if (defined ${$dsp_sub_sub}{$var1}) {
               $curval = ${$dsp_sub_sub}{$var1};
            }
            $newval = get_defines_string($ppdefs);  # lib function - fgutils02.pl
            ${$dsp_sub_sub}{$var2} = $newval;
        } else {
            # 2009/09/22 - downgraded from WARNING, to a simple ADVICE
            # prtw( "WARNING:$lnnum:$xln 'VCCLCompilerTool' DOES NOT CONTAIN(2) '$seek' [$line]\n" );
            prt( "[v04] $xln 'VCCLCompilerTool' DOES NOT CONTAIN(2) 'PreprocessorDefinitions' [$line]\n" ) if ($dbg_v04);
        }

        $seek = 'RuntimeLibrary';
        $doneseeks .= "|$seek";
        if ( defined ${$rah}{$seek} ) {
            $ppdefs = strip_quotes(trim_all(${$rah}{$seek}));
            ${$dsp_sub_sub}{$var3} = fg_get_runtime_val_2_lts($ppdefs);
        } else {
            # 2009/09/22 - downgraded from WARNING, to a simple ADVICE
            # prtw( "WARNING:$lnnum:$xln 'VCCLCompilerTool' DOES NOT CONTAIN(3) '$seek' [$line]\n" );
            prt( "[v05] $xln 'VCCLCompilerTool' DOES NOT CONTAIN(3) 'RuntimeLibrary' [$line]\n" ) if ($dbg_v05);
        }

        $seek = 'CompileAs';
        $doneseeks .= "|$seek";
        if ( defined ${$rah}{$seek} ) {
            $ppdefs = strip_quotes(trim_all(${$rah}{$seek}));
            $adddeps = ${$dsp_sub_sub}{$var3};
            if (defined $compileas{$ppdefs} ) {
               $tmp = $compileas{$ppdefs};
               if (length($tmp)) {
                   $adddeps .= " " if length($adddeps);
                   $adddeps .= "/$tmp";
               }
               $curval = '';
               if (defined ${$dsp_sub_sub}{$var3}) {
                  $curval = ${$dsp_sub_sub}{$var3};
               }
               $newval = $adddeps;
               if ($curval ne $newval) {
                  ${$dsp_sub_sub}{$var3} = $newval;
                  prt( "[v32] $xln VCCLCompilerTool:CompileAs: set [$var3] from [$curval] to [".${$dsp_sub_sub}{$var3}."]\n" ) if ($dbg_v32);
               } else {
                  prt( "[v32] $xln VCCLCompilerTool:CompileAs: NO CHANGE [$var3] as [$curval]\n" ) if ($dbg_v32);
               }
            } else {
               prtw( "WARNING:scanvc:$xln: VCCLCompilerTool:$seek: [$var3] NOT BEING SET! [$ppdefs] NOT IN 'compileas' hash [$fil]\n" );
            }
        }
        $missed = get_ct_line_hash_missed($rah,$doneseeks);
        if ($dbg_v31) {
            prt( "[v31] " );
            if (length($missed)) {
                prt( "$xln conf=[$confname]:VCCLCompilerTool: [$line]\n seeks=[$doneseeks]\n missed=[$missed] ($lhlen)\n" );
            } else {
                prt( "$xln conf=[$confname]:VCCLCompilerTool: [$line] ($lhlen)\n" ); # if ($dbg_v10);
            }
        }
    } elsif ($pname eq 'VCCustomBuildTool') {
        if (length($pname) && ($lhlen < 4)) {
            # this is ONLY <tag Name="blah" /> - so IGNORE
        } else {
            prtw( "WARNING:scanvc: MISSED CUSTOM BUILD: Check this conf=[$confname] TAG=$tag -\n [$line]\n" );
        }
    } elsif ($pname eq 'VCLinkerTool') {
        $var1 = '-NEW_LIBS-';
        $var2 = '-NEW_OUT-';
        # <Tool
        #  Name="VCLinkerTool"
        #  LinkLibraryDependencies="false"
        #  AdditionalDependencies="wsock32.lib SimGear.lib sg_d.lib ... "
        #  OutputFile="..\bin\FlightGearD.exe"
        #  LinkIncremental="0"
        #  SuppressStartupBanner="true"
        #  AdditionalLibraryDirectories="..\SimGear\$(IntDir); ..\PLIB, ..."
        #  IgnoreDefaultLibraryNames="MSVCRT" - may ONLY be in DEBUG
        #  GenerateDebugInformation="true"
        #  ProgramDatabaseFile=".\Debug/FlightGear.pdb"
        #  SubSystem="1"
        #  RandomizedBaseAddress="1"
        #  DataExecutionPrevention="0"
        #  TargetMachine="1" />
        $seek = 'AdditionalDependencies';
        if (defined ${$rah}{$seek} ) {
            $adddeps = strip_quotes(trim_all(${$rah}{$seek}));
            $adddeps =~ s/&amp;/&/g;     # 20081205 - added
            $adddeps =~ s/&quot;/"/g;    # 20081205 - added
            $newval = $adddeps;
            $curval = '';
            if (defined ${$dsp_sub_sub}{$var1}) {
               $curval = ${$dsp_sub_sub}{$var1};
            }
            if ($newval ne $curval) {
               ${$dsp_sub_sub}{$var1} = $adddeps; #  $var1 = '-NEW_LIBS-'
               prt( "[v22] $xln seek=AdditionalDependencies: Set [$var1] to [$adddeps]\n" ) if ($dbg_v22);
            }
        } else {
            prtw( "WARNING:scanvc:$xln: 'VCCLinkerTool' DOES NOT CONTAIN(4) '$seek' [$line] [$fil]\n" ) if ($dbg_v16);
        }

        $seek = 'OutputFile';
        if (defined ${$rah}{$seek} ) {
            $adddeps = strip_quotes(trim_all(${$rah}{$seek}));
            # 20090808 - handle substitution
            # EG: 39:138-149: seek=OutputFile: Set [-NEW_OUT_REL-] 
            # to [.\$(ProjectName).exe]
            $adddeps =~ s/\$\(ProjectName\)/$projname/;
            $curval = '';
            if (defined ${$dsp_sub_sub}{$var2}) {
               $curval = ${$dsp_sub_sub}{$var2};
            }
            $newval = '/out:'.$adddeps;
            if ($curval ne $newval) {
               ${$dsp_sub_sub}{$var2} = $newval;
               prt( "[v24] $xln seek=OutputFile: Set [$var2] to [$newval]\n" ) if ($dbg_v24);
            }
            $outfile = $adddeps; # set the OUTPUT file name
        } else {
           # 20090912 - downgraded to a NOTE only, and ONLY once per file
           if ( !($flag & $cf_dn_lt_t) ) {  # $dn_lt_noo
               # prtw( "WARNING:$lnnum:$xln 'VCCLinkerTool' DOES NOT CONTAIN(5) '$seek' [$line]\n" ) if ($dbg_v21);
               prt( "[v21]:lib_vcscan:$xln: 'VCCLinkerTool' DOES NOT CONTAIN(5) 'OutputFile' [$line]\n" ) if ($dbg_v21);
                $flag |= $cf_dn_lt_t;    # $dn_lt_noo = 1;
                ${$rh}{'CURR_FLAG'} |= $cf_dn_lt_t;
           }
        }

        $seek = 'AdditionalLibraryDirectories';
        if (defined ${$rah}{$seek} ) {
            # must deal with a crazy string like this -
            # AdditionalLibraryDirectories=
            # "&amp;quot,..\fltk-1.1.7\lib&amp;quot,..\SimGear.plib\Debug,
            # ..\zlib-1.2.3&amp;quot,..\plib,
            # ..\pthreads-w32-2-7-0-release&amp;quot,..\gettext\lib"
            # after quotes removed, and the first substitution
            # &quot,..\fltk-1.1.7\lib&quot,..\SimGear.plib\Debug,
            # ..\zlib-1.2.3&quot,..\plib,
            # ..\pthreads-w32-2-7-0-release&quot,..\gettext\lib
            # after next pair of subs
            # ",..\fltk-1.1.7\lib",..\SimGear.plib\Debug,
            # ..\zlib-1.2.3",..\plib,
            # ..\pthreads-w32-2-7-0-release",..\gettext\lib
            # then removing the auotes
            # ,..\fltk-1.1.7\lib,..\SimGear.plib\Debug,
            # ..\zlib-1.2.3,..\plib,
            # ..\pthreads-w32-2-7-0-release,..\gettext\lib
            $adddeps = strip_quotes(trim_all(${$rah}{$seek}));
            $adddeps =~ s/&amp;/&/g;    # 20081205 - added
            $adddeps =~ s/&quot;/"/g;   # 20081205 - added
            $adddeps =~ s/&quot/"/g;    # 20081205 - added
            $adddeps =~ s/"//g;         # 20081205 - added
            $adddeps =~ s/^,//;         # 20081205 - added
            $tmp = get_libpaths_string($adddeps); #  $var1 = '-NEW_LIBS-'
            $curval = '';
            if (defined ${$dsp_sub_sub}{$var1}) {
               $curval = ${$dsp_sub_sub}{$var1};
            }
            ${$dsp_sub_sub}{$var1} .= ' '.$tmp; #  $var1 = '-NEW_LIBS-'
            prt( "[v23] $xln seek=AdditionalLibraryDirectories: Set [$var1] to [$tmp] from [$adddeps]\n" ) if ($dbg_v23);
        } else {
            # This is very likely to be TRUE in DLL project especially, since they are DYNAMIC,
            # and do not link with any other libriaries at compile time
            prt( "[v23] $xln 'VCCLinkerTool' DOES NOT CONTAIN(6) 'AdditionalLibraryDirectories' [$line] [$fil]\n" ) if ($dbg_v23);
        }
        $seek = 'IgnoreDefaultLibraryNames';
        if (defined ${$rah}{$seek}) {
            # $var1 = '-NEW_LIBS-';
            # this would also be an indication that this was a 'exe' type project
            # Note, it may be a BLANK
            $adddeps = trim_all(strip_quotes(trim_all(${$rah}{$seek})));
            if (length($adddeps)) {
                $tmp = get_nodeflib_string($adddeps);
                $curval = '';
                if (defined ${$dsp_sub_sub}{$var1}) {
                   $curval = ${$dsp_sub_sub}{$var1};
                   ${$dsp_sub_sub}{$var1} .= ' ';
                }
                ${$dsp_sub_sub}{$var1} .= $tmp;
                prt( "[v39] $xln seek=IgnoreDefaultLibraryNames: Set [$var1] to [$tmp] from [$adddeps] prev [$curval]\n" ) if ($dbg_v39);
            }
        }

        $seek = 'SubSystem';
        if (defined ${$rah}{$seek} ) {
            $adddeps = strip_quotes(trim_all(${$rah}{$seek}));
            $apptype = adjust_app_type_per_subsystem( $dnapptype, $adddeps, $dbg_v05 );
            $flag |= $cf_apptyp2# signal, we have an APP TYPE - VERY IMPORTANT
            # subsystem determines different between 'Application' and 'Console Application'
            if (length($dnapptype)) {
               if ($dnapptype ne $apptype) {
                  prt( "[v43] $xln Project [$projname], APP_TYPE RESET per 'SubSystem' [$apptype] from [$dnapptype]...\n" ) if ($dbg_v43);
                  $dnapptype = $apptype;
               }
            } else {
               prt( "$xln Project [$projname], APP_TYPE per 'SubSystem' [$apptype]...\n" );
               $dnapptype = $apptype;
            }
            ${$rh}{'PROJECT_APTP'} = $dnapptype;
            ${$rh}{'CURR_FLAG'} |= $flag;
        } else {
            # it seems DLL vcproj do NOT have a 'SubSystem'
            # <Tool Name="VCLinkerTool"
            #  AdditionalOptions="/out:$(OutDir)/alut.dll"
            #  AdditionalDependencies="comctl32.lib Msimg32.lib Winmm.lib openal32.lib" 
            #  OutputFile=".\Debug/alut.dll" 
            #  LinkIncremental="2" 
            #  SuppressStartupBanner="true" 
            #  AdditionalLibraryDirectories="C:\Program Files\OpenAL 1.1 SDK\libs\Win32" 
            #  GenerateDebugInformation="true" 
            #  ProgramDatabaseFile=".\Debug/alut.pdb" 
            #  RandomizedBaseAddress="1" 
            #  DataExecutionPrevention="0" 
            #  ImportLibrary=".\Debug/alut.lib" 
            #  TargetMachine="1" />]
            # from [c:\FG\32\alut\admin\VisualStudioDotNET\alut\alut.vcproj]
            $seek = 'ImportLibrary';    # seems this IMPORT LIBRARY entry would be a good DLL indication!
            if (defined ${$rah}{$seek}) {
                $apptype = '';
                if (get_app_type_4_short('DLL', \$apptype) && length($apptype)) {
                    $flag |= $cf_apptyp2# signal, we have an APP TYPE - VERY IMPORTANT
                    # should be DLL
                    if (length($dnapptype)) {
                       if ($dnapptype ne $apptype) {
                          prt( "[v41] $xln Project [$projname], APP_TYPE RESET per 'ImportLibrary' [$apptype] from [$dnapptype]...\n" );
                          $dnapptype = $apptype;
                       } else {
                          prt( "[v35] $xln Project [$projname], APP_TYPE CONFIRMED per 'ImportLibrary' set to [$dnapptype]...\n" ) if ($dbg_v35);
                       }
                    } else {
                       prt( "$xln Project [$projname], APP_TYPE per 'ImportLibrary' [$apptype]...\n" );
                       $dnapptype = $apptype;
                    }
                    ${$rh}{'PROJECT_APTP'} = $dnapptype;
                    ${$rh}{'CURR_FLAG'} |= $flag;
                } else {
                    prtw( "WARNING:scanvc:$xln: FAILED TO GET 'DLL' application type string!\n" ); # if ($dbg_v18);
                    pgm_exit(1,"INTERNAL FAILURE");
                }
            } else {
                # ANOTHER STRONG indication of a DLL would be the presence of a DEF (definition) file
                $seek = 'ModuleDefinitionFile';
                if (defined ${$rah}{$seek}) {
                    $apptype = '';
                    if (get_app_type_4_short('DLL', \$apptype) && length($apptype)) {
                        $flag |= $cf_apptyp2# signal, we have an APP TYPE - VERY IMPORTANT
                        # should be DLL
                        if (length($dnapptype)) {
                           if ($dnapptype ne $apptype) {
                              prt( "[v41] $xln Project [$projname], APP_TYPE RESET per 'ModuleDefinitionFile' [$apptype] from [$dnapptype]...\n" ) if ($dbg_v41);
                              $dnapptype = $apptype;
                           } else {
                              prt( "[v35] $xln Project [$projname], APP_TYPE CONFIRMED per 'ModuleDefinitionFile' set to [$dnapptype]...\n" ) if ($dbg_v35);
                           }
                        } else {
                           prt( "[v41] $xln Project [$projname], APP_TYPE per 'ModuleDefinitionFile' [$apptype]...\n" ) if ($dbg_v41);
                           $dnapptype = $apptype;
                        }
                        ${$rh}{'PROJECT_APTP'} = $dnapptype;
                        ${$rh}{'CURR_FLAG'} |= $flag;
                    } else {
                        prtw( "WARNING:scanv:$xln: FAILED TO GET 'DLL' application type string!\n" ); # if ($dbg_v18);
                        pgm_exit(1,"INTERNAL FAILURE");
                    }
                } else {
                    # FINALLY ANOTHER STRONG indication of a DLL would be that OutputFile ends in ".dll"
                    $seek = 'OutputFile';
                    if ( length($outfile) ) {
                        if ($outfile =~ /\.dll$/i) {
                            # have a DLL indication
                            $apptype = '';
                            if (get_app_type_4_short('DLL', \$apptype) && length($apptype)) {
                                $flag |= $cf_apptyp2# signal, we have an APP TYPE - VERY IMPORTANT
                                if (length($dnapptype)) {
                                   if ($dnapptype ne $apptype) {
                                      prt( "[v41] $xln Project [$projname], APP_TYPE RESET per 'OutputFile' [$apptype] from [$dnapptype]...\n" ) if ($dbg_v41);
                                      $dnapptype = $apptype;
                                   } else {
                                      prt( "[v35] $xln Project [$projname], APP_TYPE CONFIRMED per 'OutputFile' set to [$dnapptype]...\n" ) if ($dbg_v35);
                                   }
                                } else {
                                   prt( "[v41] $xln Project [$projname], APP_TYPE per 'OutputFile' [$apptype]...\n" ) if ($dbg_v41);
                                   $dnapptype = $apptype;
                                }
                                ${$rh}{'PROJECT_APTP'} = $dnapptype;
                                ${$rh}{'CURR_FLAG'} |= $flag;
                            } else {
                                prtw( "WARNING:scanv:$xln: FAILED TO GET 'DLL' application type string!\n" ); # if ($dbg_v18);
                                pgm_exit(1,"INTERNAL FAILURE");
                            }
                        }
                    } else {
                        if (!($flag & $cf_dn_no_s)) {
                            prtw( "WARNING:scanvc:$xln: 'VCCLinkerTool' DOES NOT CONTAIN(7) 'SubSystem' NOR 'ModuleDefinitionFile' NOR 'OutputFile' [$line] [$fil]\n" ); # if ($dbg_v18);
                            $flag |= $cf_dn_no_s;
                            ${$rh}{'CURR_FLAG'} |= $flag;
                        }
                    }
                }
            }
        }
    } elsif ($pname eq 'VCLibrarianTool' ) {
       # <Tool Name="VCLibrarianTool"
       # OutputFile="Win32_LIB_Debug\zlibd.lib"
       # SuppressStartupBanner="true" />
        $var2 = '-NEW_OUT-';
        $seek = 'OutputFile';
        if (defined ${$rah}{$seek} ) {
            $adddeps = strip_quotes(trim_all(${$rah}{$seek}));
            $curval = '';
            if (defined ${$dsp_sub_sub}{$var2}) {
               $curval = ${$dsp_sub_sub}{$var2};
            }
            $newval = '/out:'.$adddeps;
            if ($curval ne $newval) {
               ${$dsp_sub_sub}{$var2} = $newval;
               prt( "[v24] $xln seek=OutputFile: Set [$var2] to [$newval]\n" ) if ($dbg_v24);
            }
        } else {
           # 20090914 - set as 15, downgraded to a NOTE only, and ONLY once per file
           # it seems this will DEFAULT TO '$(OutDir)\$(ProjectName).lib'!!!
           if ( !($flag & $cf_dn_lt_t) ) {  # $dn_lt_noo
               # prtw( "WARNING:$lnnum:$xln 'VCCLinkerTool' DOES NOT CONTAIN(5) '$seek' [$line]\n" ) if ($dbg_v21);
               prt( "NOTE:scanvc:$xln: 'VCLibrarianTool' DOES NOT CONTAIN(15) '$seek'\n[$line]\n" ); # if ($dbg_v21);
                $flag |= $cf_dn_lt_t;    # $dn_lt_noo = 1;
                ${$rh}{'CURR_FLAG'} |= $cf_dn_lt_t;
           }
        }
    } elsif ($pname eq 'VCPostBuildEventTool') {
            $var1 = '-NEW_POST-';
            #if ( !(($confname =~ /Debug/i)||($confname =~ /Release/i)) ) {
            #    prtw( "WARNING:$xln pname=[$confname] NOT Debug or Release - def to REL! [$fil]\n" );
            #}
            # <Tool
            #  Name="VCPostBuildEventTool"
            #  Description="Copy Library to plib directory"
            #  CommandLine="copy debug\*.lib ..\..\*.*&#x0D;&#x0A;copy ul.h ..\..\ul.h&#x0D;&#x0A;copy ulRTTI.h ..\..\ulRTTI.h&#x0D;&#x0A;"
            #  />
            # this will be output to the DSP, under the paticular, config, something like
            # # Begin Special Build Tool
            # SOURCE="$(InputPath)"
            # PostBuild_Desc=Copy to bin
            # PostBuild_Cmds=copy Release\*exe bin\.   copy test.h bin\.
            # # End Special Build Tool
            # 2010/01/14 = Can be 'Description="&quot;Copy Library to plib directory&quot;"' Note double QUOTES as '"', AND '&quot;'
            # or even '&quot;&amp;quot;Copy Library to plib directory&amp;quot;&quot;'
            if (( defined ${$rah}{'Description'} ) || ( defined ${$rah}{'CommandLine'} ) ) {
                $ppdefs = ""; # to 'PostBuild_Desc=';
                if ( defined ${$rah}{'Description'} ) {
                    #$ppdefs .= add_quotes(strip_quotes(trim_all(${$rah}{'Description'})));
                    $ppdefs = strip_quotes(trim_all(${$rah}{'Description'}));
                    prt("[v36] Got description: [$ppdefs]\n") if ($dbg_v36);
                    $ppdefs =~ s/&quot;/"/g;
                    $ppdefs = strip_quotes($ppdefs);
                    $ppdefs =~ s/&amp;/&/g;
                    # could strip it ALL with added, but not for now...
                    #$ppdefs =~ s/&quot;/"/g;
                    #$ppdefs = strip_quotes($ppdefs);
                    $ppdefs = add_quotes($ppdefs);
                    prt("[v36] Massaged to: [$ppdefs]\n") if ($dbg_v36);
                }
                $adddeps = ""; # to ' PostBuild_Cmds=';
                if ( defined ${$rah}{'CommandLine'} ) {
                    $adddeps = strip_quotes(trim_ends(${$rah}{'CommandLine'}));
                    $adddeps =~ s/&quot;/"/g;   # put back the quotes, if any
                    $adddeps =~ s/&#x0D;&#x0A;/\t/g;    # new line to TAB for VC6
                    $adddeps =~ s/\t$//;    # clear any END tab
                }
                prt( "[v15] $xln got POST event [$ppdefs]\n" ) if ($dbg_v15);
                $tmp = "# Begin Special Build Tool\n";
                $tmp .= "SOURCE=\"\$(InputPath)\"\n";
                $tmp .= "PostBuild_Desc=$ppdefs\n";
                # sometimes need a little 'massaging' of the command ...
                $tmp .= "PostBuild_Cmds=".massage_command3($adddeps)."\n";
                $tmp .= "# End Special Build Tool\n";
                ${$dsp_sub_sub}{$var1} = $tmp;
            }
    } elsif ($pname eq 'VCMIDLTool') {
        # perhaps to be done *TBD*
    } elsif ($pname eq 'VCResourceCompilerTool') {
        # perhaps to be done *TBD*
    } elsif ($pname eq 'VCBscMakeTool') {
        # perhaps to be done *TBD*
    } else {
        if (length($pname) && ($lhlen < 4)) {
            # this is ONLY <tag Name="blah" /> - so IGNORE
        } else {
            # only show ONCE for each NO HANDLED
            if (! defined $not_handled{$pname}) {
                prtw( "WARNING:scanvc:$xln: conf=[$confname] Tag=[$tag] [$pname] NOT HANDLED! [$line] ($lhlen)\n" );
                $not_handled{$pname} = 1;
            }
        }
    }
}

sub process_vc_file_tool_tag($$) {
    my ($rh,$fconf) = @_;
    my ($xln,$rah,$tag,$pname,$fil,$projname,$line,$flag);
    extract_curr_items($rh,\$xln,\$rah,\$tag,\$pname,\$fil,\$projname,\$line,\$flag);
    my ($seek);
    my ($ppdefs,$curval,$newval);
    my ($adddeps);
    my ($adddefs,$tmp); # 2010/05/01 
    my $last_src = ${$rh}{'CURR_LSRC'};
    my $last_nm  = ${$rh}{'CURR_LNME'};
    my $last_dir = ${$rh}{'CURR_LDIR'};
    my $last_ext = ${$rh}{'CURR_LEXT'};
    my $dsp_sub_sub = ${$rh}{'CURR_DSUB'};
    my $lhlen = scalar keys(%{$rah});   # get item count in line hash

    if ($pname eq 'VCCLCompilerTool') {
        prt( "[v34] $xln file: 'VCCLCompilerTool' [$line] IGNORED CHECK ($lhlen)\n" ) if ($dbg_v34);
    } elsif ($pname eq 'VCCustomBuildTool') {
        my ($nm,$dir);
        my $pfhr = get_per_file_hash($rh);  # 'CURR_PFHR'
        if (( defined ${$rah}{'Description'} ) || ( defined ${$rah}{'CommandLine'} ) ) {
            $ppdefs = ""; # to 'PostBuild_Desc=';
            $seek = 'Description';
            if ( defined ${$rah}{$seek} ) {
                $ppdefs .= strip_quotes(trim_all(${$rah}{$seek}));
            }
            $seek = 'CommandLine';
            $adddeps = ""; # to ' PostBuild_Cmds=';
            if ( defined ${$rah}{$seek} ) {
                $adddeps = strip_quotes(trim_ends(${$rah}{$seek}));
                $adddeps =~ s/&quot;/"/g;   # put back the quotes, if any
                $adddeps =~ s/&#x0D;&#x0A;/\t/g;    # new line to TAB for VC6
                $adddeps =~ s/\t$//;    # clear any END tab
            }
            $adddefs = '$(IntDir)';
            $seek = 'Outputs';
            if ( defined ${$rah}{$seek} ) {
                $adddefs = strip_quotes(trim_all(${$rah}{$seek}));
            }
            # this seems to be something like -
            # $(IntDir)\asm\$(InputName).obj, but for the DSP file the '\$(InputName).obj' seems ASSUMED,
            # and the $(IndDir) is replaced with an actual DIRECTORY, so...
            if ($adddefs =~ /\.obj$/i) {
                ($nm,$dir) = fileparse( $adddefs );
                $dir =~ s/(\\|\/)$//;
                $adddefs = $dir;
            }
            if ($adddefs =~ /\$\(IntDir\)/) {
                if (defined ${$dsp_sub_sub}{'-NEW_INTER-'}) {
                    $dir = strip_quotes(${$dsp_sub_sub}{'-NEW_INTER-'});
                    $dir =~ s/(\\|\/)$//;
                    $adddefs =~ s/\$\(IntDir\)/$dir/;
                }
            }
            $tmp = "# Begin Custom Build - $ppdefs\n";
            $tmp .= "IntDir=$adddefs\n";
            $tmp .= "Inputpath=$last_src\n";
            $tmp .= "InputName=$last_nm\n\n";
            $tmp .= "\"\$(IntDir)\\\$(InputName).obj\" : \$(SOURCE) \"\$(INTDIR)\" \"\$(OUTDIR)\"\n";
            $tmp .= "\t".massage_command3($adddeps)."\n\n";
            $tmp .= "# End Custom Build\n";
            prt( "[v27] $xln got CUSTOM event [$pname] [$fconf] [$adddefs]\n" ) if ($dbg_v27);
            prt( "[v28] CUSTOM event [$tmp]\n" ) if ($dbg_v28);
            if (defined ${$pfhr}{$fconf}) {
                prtw("WARNING:scanvc: Already have [$fconf] in per_file_hash!\n");
            }
            ${$pfhr}{$fconf} = $tmp# store it for later
        } else {
            $tmp = scalar keys(%{$rah});
            if (length($pname) && ($tmp < 4)) {
                # ignore is just <tag name="blah" />, but empty otherwise
            } else {
                prtw( "WARNING:scanvc: Deal with TAG=$tag - [$line] NO Decription or Command line! ($tmp)\n file=[$fil]\n" );
            }
        }
    } elsif ($pname eq 'VCResourceCompilerTool') {
        prt( "[v34] $xln file: 'VCResourceCompilerTool' [$line] IGNORED CHECK (line=$lhlen)\n" ) if ($dbg_v34);
    } else {
        prtw( "WARNING:scanvc:$xln: [$pname] NOT HANDLED! (line=$lhlen)\n" );
    }
}

sub get_cfgs_array_order($$) {
    my ($rcfgs,$rkarr) = @_;
    my $cnt = scalar @{$rcfgs};
    my ($i, $cfg, $test, @arr);
    @arr = ();
    push(@arr,-99);
    push(@arr,-99);
    return 0 if ($cnt < 2);
    $test = 0;  # 2010/05/05 - add init of var
    for ($i = 0; $i < $cnt; $i++) {
        $cfg = ${$rcfgs}[$i][0];
        if ($cfg eq 'Release') {
            $test |= 1;
            $arr[0] = $i;
        } elsif ($cfg eq 'Debug') {
            $test |= 2;
            $arr[1] = $i;
        } else {
            push(@arr,$i);
        }
    }
    if ($test == 3) {   # found both 'Release' and 'Debug'
        # then enforce the ORDER 'Release, Debug, Others
        @{$rkarr} = @arr;   # copy the index array
        return 1;
    }
    return 0;
}

#add_any_per_file_items( $rdsp_current_sub, \%per_file_hash, $src_ref,
#                \@configs, $last_fpos, $projname );
sub add_any_per_file_items3($) {
    my ($rh) = @_;
    my $pfhr = get_per_file_hash($rh);  # 'CURR_PFHR'
    my $xln  = get_current_xline_stg($rh);
    my @karr = keys(%{$pfhr});
    my $kcnt = scalar @karr;
    my $modstg = $xln."scanvc:add_any_per_file_items3:";
    my ($cfg);  # 2010/05/01 
    if ($kcnt) {
        my ($rcfgs,$ccnt,$key,$i,$fnd,$tmp,$pname);
        $rcfgs = get_project_configs($rh);   # 'PROJECT_CFGS'
        $pname = svc_get_project_name_stg($rh);  # 'PROJECT_NAME'
        # push(@{$rcfgs}, [ $confname, $var1, $conf, $dsp_sub_sub ]);
        $ccnt = scalar @{$rcfgs};
        $fnd = 0;
        foreach $key (@karr) {
            for ($i = 0; $i < $ccnt; $i++) {
                if (${$rcfgs}[$i][2] eq $key) {
                    $fnd++;
                    last;
                }
            }
        }
        if ($fnd == $kcnt) {
            $tmp = '';
            @karr = (); # clear this array
            if ( get_cfgs_array_order($rcfgs,\@karr) && (scalar @karr == $kcnt) ) {
                $fnd = 0;
                foreach $i (@karr) {
                    $key = ${$rcfgs}[$i][2];
                    $cfg = ${$rcfgs}[$i][0];
                    if ($fnd == 0) {
                        $tmp .= "\n!IF ";   # Release
                    } else {
                        $tmp .= "!ELSEIF "; # Debug, and others
                    }
                    $tmp .= "\"\$(CFG)\" == \"$pname - Win32 $cfg\"\n\n";
                    if (defined ${$pfhr}{$key}) {
                        $tmp .= ${$pfhr}{$key};
                    }
                    $tmp .= "\n";
                    $fnd++;
                }
            } else {
                for ($i = 0; $i < $ccnt; $i++) {
                    $key = ${$rcfgs}[$i][2];
                    $cfg = ${$rcfgs}[$i][0];
                    if ($i == 0) {
                        $tmp .= "\n!IF ";
                    } else {
                        $tmp .= "!ELSEIF ";
                    }
                    $tmp .= "\"\$(CFG)\" == \"$pname - Win32 $cfg\"\n\n";
                    if (defined ${$pfhr}{$key}) {
                        $tmp .= ${$pfhr}{$key};
                    }
                    $tmp .= "\n";
                }
            }
            $tmp .= "!ENDIF \n\n";
            my $srcs = get_project_srcs_ref($rh); # 'PROJECT_SRCS'
            my $coff = get_last_src_offset($rh);  # 'CURR_LOFF' # last/current source OFFSET
            #                     0          1       2       3  4
            # push(@{$src_ref}, [ $last_src, $fname, $flist, 0, '' ]); # and PUSH onto SOURCE stack
            $key = ${$srcs}[$coff][0];
            ${$srcs}[$coff][4] = $tmp;
            prt( "[v29] $xln Added CUSTOM build for source [$key]\n" ) if ($dbg_v29);
            prt( "[v30] CUSTOM build [$tmp]\n" ) if ($dbg_v30);
        } else {
            prtw("WARNING:scanvc: $kcnt keys NOT handled in per file hash! Only found $fnd!!\n");
        }
    } else {
        prt("[v11] $xln NO keys in per file hash...\n") if ($dbg_v11);
    }
}

sub get_xln_stg($$) {
    my ($lnn,$npair) = @_; # "$lnnum:".${$rlm}{$lnnum};
    my @a = split('-',$npair);
    my $xln = sprintf("%03d:%03d-%03d:", $lnn, $a[0], $a[1]);
    return $xln;
}

sub get_clean_seek_item($) {
    my ($txt) = shift;
    $txt =~ s/>$//; # 2010-04-23 - ensure any trailing '>' is removed
    $txt = strip_quotes(trim_all($txt));
    return $txt;
}

# see sub svc_xml_to_lines($$), which does NOT process quotes - maybe it should
sub get_new_xml_lines($) {
    my ($rlines) = shift;
    my ($i,$line,$len,$ch,$inquot,$qc,$lnn,$nline,$intag);
    $lnn = 0;
    $inquot = 0;
    $nline = '';
    $intag = 0;
    my @nlines =();
    foreach $line (@{$rlines}) {
        $lnn++;
        $line = trim_all($line);
        $len = length($line);
        for ($i = 0; $i < $len; $i++) {
            $ch = substr($line,$i,1);
            if ($inquot) {
                $nline .= $ch;
                $inquot = 0 if ($ch eq $qc);
            } elsif ($intag) {
                $nline .= $ch;
                if ($ch eq '>') {
                    # end of TAG
                    push(@nlines,[$nline,$lnn]);
                    $nline = '';
                    $intag = 0;
                } elsif (($ch eq '"')||($ch eq "'")) {
                    $qc = $ch;
                    $inquot = 1;
                }
            } else {
                if ($ch eq '<') {
                    $intag = 1;
                    if (length($nline)) {
                        push(@nlines,[$nline,$lnn]);
                    }
                    $nline = $ch;   # start item
                } elsif (($ch eq '"')||($ch eq "'")) {
                    $nline .= $ch;   # add quote
                    $qc = $ch;
                    $inquot = 1;
                } else {
                    if ($ch =~ /\s/) {
                       $nline .= $ch if (length($nline));
                    } else {
                       $nline .= $ch;
                    }
                }
            }
        } # for each char in line
        push(@nlines,[$nline,$lnn]) if (length($nline));
        if ($inquot) {
            prtw("WARNING: Line [$line] end while in QUOTE [$qc]\n");
            $inquot = 0;
        }
        #if ($intag) {
        #    prtw("WARNING: Line [$line] end while in TAG\n");
        #}
        $nline .= ' ' if (length($nline));
    }
    push(@nlines,[$nline,$lnn]) if (length($nline));
    $i = scalar @{$rlines};
    $len = scalar @nlines;
    prt("XML $i lines, split to $len lines\n");
    if ($write_temp_xml2) {
        my $tmpxml = "C:\\GTools\\perl\\tempvcx2.xml";
        ### $nline = join("\n",@nlines)."\n";
        $nline = '';
        for ($i = 0; $i < $len; $i++) {
            $line = $nlines[$i][0];
            $nline .= "$line\n";
        }
        write2file($nline,$tmpxml);
        prt( "Written relined XML to '$tmpxml'\n" );
    }
    return \@nlines;
}

# sub pre_process_VCPROJ($$$) {
sub process_VC_lines($$$) {
    my ($fil, $rlines, $rlm) = @_;
    my ($line, @attribs, %atthash);
    my ($tag, $pname);
    my $invcproj = 0;
    my $projname = '';
    my $adddeps = '';
    my $adddefs = '';
    my $do_pre_pro = 1;
    my $lnnum = 0;
    my $xln = '';
    my $rh = get_default_ref_hash($fil);
    my $infile = 0;
    my $infilter = 0;
    my $inconfig = 0;
    my $fname = '';
    my $flist = '';
    my $fconf = '';
    my ($tmp);
    my $last_src = '';
    my ($last_nm,$last_dir,$last_ext,$src_ref);
    my $confname = '';
    my $conf = '';
    $g_sc_infiles = 0;
    $g_sc_inconfigs = 0;
    $g_sc_infconf = 0;
    my %p_f_h = ();
    my $pfhr = \%p_f_h;
    my ($seek,$var1); # 2010/05/01 
    my ($max,$i); # 25/11/2010
    $max = scalar @{$rlines};
    for ($i = 0; $i < $max; $i++) {
        $line = ${$rlines}[$i];
        $lnnum++;
        $xln = get_xln_stg($lnnum,${$rlm}{$lnnum}); # "$lnnum:".${$rlm}{$lnnum};
        @attribs = space_split($line);
        %atthash = array_2_hash_on_equals(@attribs);
        $tag = $attribs[0];
        #$pname = (defined $atthash{'Name'}) ? strip_quotes(trim_all($atthash{'Name'})) : '';
        $pname = (defined $atthash{'Name'}) ? get_clean_seek_item($atthash{'Name'}) : '';
        ${$rh}{'CURR_LINE'} = $xln;
        ${$rh}{'CURR_TEXT'} = $line;
        ${$rh}{'CURR_HASH'} = \%atthash;
        ${$rh}{'CURR_TAG'}  = $tag;
        ${$rh}{'CURR_NAME'} = $pname;
        ${$rh}{'CURR_PFHR'} = $pfhr;
        # <Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
        if ($tag =~ /<Project/) {
            if (defined $atthash{'ToolsVersion'}) {
                $tmp = $atthash{'ToolsVersion'};
                prt("Got 'ToolsVersion' = $tmp\n");
                #### process_VC10_lines($fil,$rlines,$rlm);
                pgm_exit(1,"ERROR: MSVC10 Project file NOT yet supported here...\n file [$fil]\n");
            }
        }
    }
    if ($do_pre_pro) {
        $fname = '<none>';
        $flist = '<none>';
        $lnnum = 0;
        for ($i = 0; $i < $max; $i++) {
            $line = ${$rlines}[$i];
            $lnnum++;
            $xln = get_xln_stg($lnnum,${$rlm}{$lnnum}); # "$lnnum:".${$rlm}{$lnnum};
            @attribs = space_split($line);
            %atthash = array_2_hash_on_equals(@attribs);
            $tag = $attribs[0];
            #$pname = (defined $atthash{'Name'}) ? strip_quotes(trim_all($atthash{'Name'})) : '';
            $pname = (defined $atthash{'Name'}) ? get_clean_seek_item($atthash{'Name'}) : '';
            ${$rh}{'CURR_LINE'} = $xln;
            ${$rh}{'CURR_TEXT'} = $line;
            ${$rh}{'CURR_HASH'} = \%atthash;
            ${$rh}{'CURR_TAG'}  = $tag;
            ${$rh}{'CURR_NAME'} = $pname;
            ${$rh}{'CURR_PFHR'} = $pfhr;
            if ($invcproj) {
                if ($tag =~ /<\/VisualStudioProject/) {
                    $invcproj = 0;
                    $tmp     = ${$rh}{'PROJECT_NAME'};
                    $adddefs = ${$rh}{'PROJECT_TYPE'};
                    $adddeps = ${$rh}{'PROJECT_VERS'};
                    prt( "[v01] $xln End VisualStudioProject name=[$tmp], type=[$adddefs], vers=[$adddeps]\n" ) if ($dbg_v01);
                } else {
                    # =====================================================================
                    # *** IN THE PROJECT ***
                    if ($g_sc_inconfigs) {
                        if ($tag =~ /<\/Configurations/) {
                            $g_sc_inconfigs = 0;
                            prt( "[v02] $xln End Configurations ($tag)\n" ) if ($dbg_v02);
                        } else {
                            # ==================================================================
                            # *** IN CONFIGURATIONS ***
                            if ($inconfig) {
                                if ($tag =~ /^<\/Configuration>/) {
                                    prt( "[v06] $xln End ConfigurationName=[$confname] conf=[$conf] [$line] ...($tag)\n" ) if ($dbg_v06);
                                    $inconfig = 0;
                                } else {
                                    if ($tag =~ /^<Tool/) {
                                        process_vc_conf_tool_tag($rh);
                                    } else {
                                        prt( "$xln DEAL with $tag [$conf] [$line] ($tag)\n" );
                                    }
                                }
                            } elsif ($tag =~ /^<Configuration$/) {
                                #$conf = $pname;
                                #@arr = split(/\|/,$pname);
                                #$confname = $arr[0];
                                #prt( "$xln Bgn ConfigurationName=[$confname] conf=[$conf] [$line] ...($tag)\n" );
                                add_vs_config_item($rh);
                                $confname = ${$rh}{'CURR_CONF'};
                                $conf     = ${$rh}{'CURR_CON1'};
                                $inconfig = 1;
                            }
                            # ==================================================================
                        }
                    } elsif ($tag =~ /<Configurations/) {
                        $g_sc_inconfigs = 1;
                        prt( "[v02] $xln Bgn Configurations ($tag)\n" ) if ($dbg_v02);
                    }
                    if ($g_sc_infiles) {
                        if ($tag =~ /\/Files/) {
                            $g_sc_infiles = 0;
                            prt( "[v12] $xln End Files\n" ) if ($dbg_v12);
                        } else {
                            # ==================================================================
                            # *** IN FILES ***
                            if ($tag =~ /^<Filter/) {
                                $fname = $pname;
                                $flist = '';
                                $seek = 'Filter';
                                if (defined $atthash{$seek} ) {
                                    $flist = strip_quotes(trim_all($atthash{$seek}));
                                    # handle this Filter="&quot;h;hpp;hxx;hm;inl&quot;&gt;"
                                    $flist =~ s/&gt;//g;    # 20081205 - remove this, if exists
                                    $flist =~ s/&quot;/"/g; # 20081205 - put QUOTES back
                                    $flist = strip_quotes($flist);  # now again remove them
                                } else {
                                    # example: alut.vcproj
                                    # <Filter Name="ALUT Header">
                                    # <File RelativePath="..\..\..\include\AL\alut.h">
                                    # </File></Filter>
                                    if (!$flist_done_once) {
                                        prtw( "WARNING:scanvc:$xln: DOES NOT CONTAIN(12) '$seek'? [$line] [$fil]\n" ); # if ($dbg_v17);
                                        $flist_done_once++;
                                    }
                                }
                                # prt( "$lnnum:$xln ENTER Filter name=[$fname] list=[$flist]\n" ) if ($dbg_v11);
                                prt( "[v07] $xln Bgn Filter name=[$fname] list=[$flist] ($tag)\n" ) if ($dbg_v07);
                                $infilter = 1;
                            } elsif ($tag =~ /^<\/Filter/) {
                                $infilter = 0;
                                prt( "[v07] $xln End Filter ($tag)\n" ) if ($dbg_v07);
                                $fname = '<none>';
                                $flist = '<none>';
                            } elsif ($tag =~ /^<File$/) {
                                $seek = 'RelativePath';
                                if (defined $atthash{$seek}) {
                                    $var1 = $atthash{$seek};
                                    $var1 =~ s/>$//;
                                    $last_src = strip_dotrel(strip_quotes(trim_all($var1)));
                                    # <File RelativePath="..\..\..\include\AL\alut.h">
                                    # this is the RELATIVE PATH - relative to the vcproj file being scanned
                                    # Now would be a good time to ADJUST this PATH, for any NEW location
                                    # of the final DSP file!!! BUT, this is done back in vcproj05.pl
                                    # in the sub chk_relative_paths()...
                                    # =========================
                                    ($last_nm,$last_dir,$last_ext) = fileparse( $last_src, qr/\.[^.]*/ );
                                    # =========================
                                    $src_ref = get_project_srcs_ref($rh); # 'PROJECT_SRCS'
                                    ${$rh}{'CURR_LOFF'} = scalar @{$src_ref};   # get current source OFFSET
                                    # *** STORING SOURCE ***
                                    push(@{$src_ref}, [ $last_src, $fname, $flist, 0, '' ]); # and PUSH onto SOURCE stack
                                    ${$rh}{'CURR_LSRC'} = $last_src;
                                    ${$rh}{'CURR_LNME'} = $last_nm;
                                    ${$rh}{'CURR_LDIR'} = $last_dir;
                                    ${$rh}{'CURR_LEXT'} = $last_ext;
                                } else {
                                    prtw( "ERROR:scanvc:$xln: NO ITEM(1) '$seek'? [$line] [$fil]\n" );
                                    pgm_exit(1, "NO FILE NAME FOUND!\n" );
                                }
                                $infile = 1;
                                prt( "[v08] $xln Bgn File [$last_src] ($tag)\n" ) if ($dbg_v08);
                            } elsif ($tag =~ /^<\/File>/) {
                                prt( "[v08] $xln End File ($tag)\n" ) if ($dbg_v08);
                                #add_any_per_file_items( $rdsp_current_sub, \%per_file_hash, $src_ref,
                                #                \@configs, $last_fpos, $projname );
                                add_any_per_file_items3($rh);
                                # %p_f_h = ();
                                %{$pfhr} = ();
                                $infile = 0;
                            } elsif ($tag =~ /^<FileConfiguration/) {
                                $g_sc_infconf = 1;
                                prt( "[v09] $xln Bgn FileConfiguration [$last_src] ($tag)\n" ) if ($dbg_v09);
                                $fconf = $pname;
                                $seek = 'ExcludedFromBuild';
                                $adddefs = '';
                                if (defined $atthash{$seek} ) {
                                    #$adddefs = strip_quotes(trim_all($atthash{$seek}));
                                    $adddefs = get_clean_seek_item($atthash{$seek});
                                    if (length($adddefs) && ($adddefs =~ /true/)) {
                                        ${$src_ref}[-1][3] = 1;
                                        prt( "[v10] $xln Last = $last_src=[".${$src_ref}[-1][0]."] $fconf ExcludedFromBuild = $adddefs\n" ) if ($dbg_v10);
                                    }
                                }
                            } elsif ($tag =~ /^<\/FileConfiguration/) {
                                $g_sc_infconf = 0;
                                prt( "[v09] $xln End FileConfiguration [$last_src] ($tag)\n" ) if ($dbg_v09);
                            } elsif ($tag =~ /^<Tool/) {
                                if ($infile && $g_sc_infconf) {
                                    process_vc_file_tool_tag($rh,$fconf);
                                } else {
                                    prtw( "WARNING:scanvc:$xln: In  Tool [$pname] BUT NOT in file and conf! [$last_src] ($tag)\n" );
                                }
                            } else {
                                prtw( "WARNING:scanvc:$xln:infile TAG=[$tag] NOT HANDLED! \n" );
                            }
                            # ==================================================================
                        }
                    } elsif ($tag =~ /<Files/) {
                        $g_sc_infiles = 1;
                        prt( "[v12] $xln Bgn Files ($tag)\n" ) if ($dbg_v12);
                    }
                    # =====================================================================
                }
            } elsif ($tag =~ /<VisualStudioProject/) {
                $invcproj = 1;
                add_vs_project_items($rh, \%atthash, $xln, $fil);
                if ( (!defined ${$rh}{'PROJECT_NAME'}) || (length(trim_all(${$rh}{'PROJECT_NAME'})) == 0) ) {
                    prt( "ERROR: NO PPROJECT NAME FOUND!\n" );
                    pgm_exit(1,"NO PROJECT NAME!");
                }
                $projname = ${$rh}{'PROJECT_NAME'};
                prt( "[v38] Processing project [$projname]...\n" ) if ($dbg_v38);
            }
        }
    }
    prt("[v37] Done process_VC_lines...\n") if ($dbg_v37);
    return $rh;
}

sub svc_xml_to_lines($$) {
    my ($rlm, $rlns) = @_;
    my $intag = 0;
    my $text = '';
    my @nlines = ();
    my ($fln, $ln, $ch, $pch, $nch, $len, $i, $i2, $tag, $xml, $dnx);
    my ($lnnm, $lnb, $nlnm);
    $pch = '';
    $nch = '';
    $tag = '';
    $xml = '';
    $dnx = 0;
    $lnnm = 0;
    $nlnm = 0;
    $lnb = 0;
    my $nxtxt = '';
    foreach $fln (@{$rlns}) {
        chomp $fln;
        $ln = trim_all($fln);
        $len = length($ln);
        $lnnm++;    # count another xml line
        for ($i = 0; $i < $len; $i++) {
            $i2 = $i + 1;
            $ch = substr($ln,$i,1);
            $nch = (($i2 < $len) ? substr($ln,$i2,1) : ' ');
            if ($intag) {
                # on first SPACE
                $tag .= $ch;
                if ($ch eq '>') {
                    # end of XML tag
                    $nlnm++;
                    push(@nlines,$tag);
                    ### prt( "push(\@xlnmap, [ $nlnm, $lnb, $lnnm ]); # each NEW line has BEGIN and END\n" );
                    $$rlm{$nlnm} = "$lnb-$lnnm";    # each NEW line has BEGIN and END
                    $nxtxt .= "$lnb-$lnnm: [$tag]\n";
                    $tag = '';
                    $intag = 0;
                    $xml = '';
                }
            } else {
                if ($ch eq '<') {
                    $tag = $ch; # start a tag line
                    $intag = 1; # signal in a tag
                    $xml = '';
                    $dnx = 0;
                    $lnb = $lnnm;    # set the BEGIN xml line
                }
            }
            $pch = $ch;
        }
        # done a line - this is like a SPACE
        if ($intag && length($tag)) {
            $tag .= ' ' if !($tag =~ /\s$/);
        }
    }
    if (length($tag)) {
        prtw("WARNING:scanvc: xml re-lining error! Left pending tag [$tag]\nin $g_sc_act_vcproj file ...\n");
    }
    $dnx = scalar @nlines;
    if ($dnx < 5) {
        prt("ERROR: Input file [$g_sc_act_vcproj] only has $dnx lines!\n");
        pgm_exit(1, "INPUT TOO SMALL!!!\n");
    }
    if ($write_temp_xml) {
        my $tmpxml = "C:\\GTools\\perl\\tempvcx.xml";
        if (! -f $tmpxml) {
            write2file($nxtxt,$tmpxml);
            prt( "Written relined XML to '$tmpxml'\n" );
        }
    }
    return @nlines;
}


sub process_VCPROJ3 {
    my ($fil) = shift;
    $g_sc_act_vcproj = $fil;
    ($g_sc_act_name,$g_sc_act_path) = fileparse($fil);
    $g_sc_act_path = cwd() if ($g_sc_act_path =~ /^\.(\\|\/)$/);
    $g_sc_act_path .= "\\" if (!($g_sc_act_path =~ /(\\|\/)$/));
    my ($new_ref);
    if (open INF, "<$fil") {
        my %lnmap = ();
        my @lines = <INF>;
        close INF;
        my $xlncnt = scalar @lines;
        # hmmmm, svc_xml_to_lines() does NOT account for text between TAGS
        # so this ONLY works for the old style vcproj files
        # try new service
        ### TODO ***TBD*** ANOTHER DAY
        # my $rnlines = get_new_xml_lines(\@lines);
        @lines = svc_xml_to_lines(\%lnmap, \@lines);
        my $lncnt = scalar @lines;
        prt( "\nProcessing file [$fil], $lncnt lines ($xlncnt) ...\n" ) if ($dbg_v42);
        $new_ref = process_VC_lines( $fil, \@lines, \%lnmap );
    } else {
        mydie( "ERROR: Unable to open $fil ... $! ... check name, location ...\n" );
    }
    return $new_ref;
}

1;

# lib_vcscan.pl

index -|- top

checked by tidy  Valid HTML 4.01 Transitional