#!/usr/bin/perl -w
# lib_amscan.pl
# Library of services for scanning Makefile.am files
# 17/04/2012 - NEW $use_ouput_change = 0(def) (sub set_output_change($)) to add auto on linker output like out:bin\foo.exe
# 02/03/2012 - # if ($auto_on & 2) { # = $auto_on_flag - # modifying the library project name - should this be done???
# added service to do this mod sub get_modified_library_name($)
# 14/10/2011 - Elevate output 'AM files processed yielded NO programs nor libraries!' to a WARNING 
# 03/08/2011 - FIX20110803 - Found macro in Makefile.am like E00 = # src1.c - This should yield NO source
# FIX20110421 - eliminate dupes in a sometimes very long set of libs, and libpaths...
# 28/01/2011 - Fix in PGM: section
# 25/12/2010 - more robust, when NO 'Makefile.am' found...
# 04/10/2010 - put more to missed source file
# 15/09/2010 - continuing to add things - like try target scan if no libs/progs
# 01/09/2010 geoff mclane http://geoffair.net/mperl
use strict;
use warnings;
use File::Basename; # to split path into ($name, $dir) = fileparse($ff); or ($nm,$dir,$ext) = fileparse( $fil, qr/\.[^.]*/ );
use Cwd;
my $cwd = cwd();

my $find_bad_source = 1;
my $show_dup_title = 0;
my $max_of_type = 30;
my $avoid_adding_macro = 0;
my $set_srcdir_local = 1;
my $cairo_special_fix = 1;
my $use_output_change = 0;  # due to MSVC10 warning, do NOT change linker output

sub set_output_change($) { $use_output_change = shift; }

our ($dbg_s01, $dbg_s02, $dbg_s03, $dbg_s04, $dbg_s05, $dbg_s06, $dbg_s07, $dbg_s08,
     $dbg_s09, $dbg_s10, $dbg_s11, $dbg_s12, $dbg_s13, $dbg_s14, $dbg_s15, $dbg_s16,
     $dbg_s17, $dbg_s18, $dbg_s19, $dbg_s20, $dbg_s21, $dbg_s22, $dbg_s23, $dbg_s24
     );

# CONSTANTS
my $IF_PATTERN = "^if[ \t]+\([A-Za-z][A-Za-z0-9_]*\)[ \t]*\(#.*\)?\$";
my $IFD_PATTERN = "^ifdef[ \t]+\([A-Za-z][A-Za-z0-9_]*\)[ \t]*\(#.*\)?\$";
my $IFEQ_PATTERN = "^ifeq[ \t]+\(.+\)[ \t]*\(#.*\)?\$";
my $IFNEQ_PATTERN = "^ifneq[ \t]+\(.+\)[ \t]*\(#.*\)?\$";
my $NIF_PATTERN = "^if[ \t]+!(.+)\$";
my $NIF_PATTERN2 = "^if!\\s+(.+)\$";
my $ELSE_PATTERN = "^else[ \t]*\(#.*\)?\$";
my $ENDIF_PATTERN = "^endif[ \t]*\(#.*\)?\$";
my $PATH_PATTERN = '(-|\\w|/|\\.)+';
my $INCLUDE_PATTERN = "^include[ \t]+((\\\$\\\(top_srcdir\\\)/${PATH_PATTERN})|(\\\$\\\(srcdir\\\)/${PATH_PATTERN})|([^/\\\$]${PATH_PATTERN}))[ \t]*(#.*)?\$";
my $INCLUDE_PATTERN2 = "^\\s*include\\s+(.+)\$";

# FORWARD
sub am_process_AM_file($$);

#####################################################
#####################################################
# FOR DEBUG
my $am_dbg_base = 'dbg_s';
sub am_set_dbg_base($) { $am_dbg_base = shift; }
sub am_dbg_val_var($) {
    my $val = shift;
    my $var = $am_dbg_base;
    if ($val < 10) {
        $var .= "0$val";
    } else {
        $var .= "$val";
    }
    return $var;
}
sub am_get_dbg_var($) {
    my $val = shift;
    my $var = am_dbg_val_var($val);
    my $res = -1;
    # from : http://perldoc.perl.org/functions/eval.html
    if (eval "defined \$$var") {
        $res = eval "\$$var";
    }
    return $res;
}

sub am_get_dbg_stg() {
    my $s = '';
    my ($i,$res,$i2);
    for ($i = 1; ;$i++) {
        $res = am_get_dbg_var($i);
        last if ($res == -1);
        if ($i < 10) {
            $i2 = "0$i";
        } else {
            $i2 = "$i";
        }
        if ($res) {
            $s .= "$i2 ";
        }
    }
    return $s;
}

sub am_get_dbg_range() {
    my ($i,$res);
    for ($i = 1; ;$i++) {
        $res = am_get_dbg_var($i);
        last if ($res == -1);
    }
    return $i - 1;
}

sub am_set_dbg_var($) {
    my $val = shift;
    my $var = am_dbg_val_var($val);
    # from : http://perldoc.perl.org/functions/eval.html
    # NOT $$var++; # does not work!
    if (eval "defined \$$var") {
        eval "\$$var = 1";
    } else {
        #print "ERROR: \$$var does NOT exist\n";
        return 0;
    }
    return 1;
}

sub am_clear_dbg_var($) {
    my $val = shift;
    my $var = am_dbg_val_var($val);
    # from : http://perldoc.perl.org/functions/eval.html
    # NOT $$var++; # does not work!
    if (eval "defined \$$var") {
        eval "\$$var = 0";
    } else {
        #print "ERROR: \$$var does NOT exist\n";
        return 0;
    }
    return 1;
}

sub am_set_all_dbg_on() {
    my ($i,$res);
    for ($i = 1; ;$i++) {
        $res = am_set_dbg_var($i);
        last if (!$res);
    }
}

sub am_set_all_dbg_off() {
    my ($i,$res);
    for ($i = 1; ;$i++) {
        $res = am_clear_dbg_var($i);
        last if (!$res);
    }
}

######################################################
### DIRECTORY SCAN STUFF - moved to lib_acscan.pl
#####################################################

## SUBSTITUTIONS
## =============
# skip these [-@(for i in $(srcdir)/test/HTML/* ; do n...], etc
sub skip_these_strings($) {
    my ($txt) = @_;
    return 1 if ($txt =~ /\bfor\s+\w+\s+in\s+/);
    return 1 if ($txt =~ /^-\@\(for/);
    return 1 if ($txt =~ /^-*\@\(if\s+\[/);
    return 1 if ($txt =~ /^-\@\(\$\(top/);
    return 1 if ($txt =~ /`.+`/);   # shell quite '`'
    return 1 if ($txt =~ /if\s+test\s+(.+);\s+then/);
    return 1 if ((($txt =~ /\brm\b/)||($txt =~ /\bmv\b/)) && ($txt =~ /\bsed\b/));
    return 0;
}

# AM macro split
# 1: $(MACRO)
# 2: ${MACRO}
# 3: @MACRO@
sub am_macro_split($$) {
    my ($txt,$add) = @_;
    my @arr = ();
    my $len = length($txt);
    my ($i,$tag,$ch,,$nc,$mac,$k);
    $tag = '';
    for ($i = 0; $i < $len; $i++) {
        $ch = substr($txt,$i,1);
        if ($ch eq '$') {
            $k = $i + 1;
            if ((($k+3) < $len)&&(substr($txt,$k,1) eq '(')) {
                $k++;
                $mac = '$(';
                for (; $k < $len; $k++) {
                    $nc = substr($txt,$k,1);
                    $mac .= $nc;
                    last if ($nc eq ')');
                    last if ($nc =~ /\W/);
                }
                if ($nc eq ')') {
                    push(@arr,$tag) if (length($tag) && $add);
                    $tag = '';
                    push(@arr,$mac);
                    $ch = '';
                    $i = $k;
                }
            } elsif ((($k+3) < $len)&&(substr($txt,$k,1) eq '{')) {
                $k++;
                $mac = '${';
                for (; $k < $len; $k++) {
                    $nc = substr($txt,$k,1);
                    $mac .= $nc;
                    last if ($nc eq '}');
                    last if ($nc =~ /\W/);
                }
                if ($nc eq '}') {
                    push(@arr,$tag) if (length($tag) && $add);
                    $tag = '';
                    push(@arr,$mac);
                    $ch = '';
                    $i = $k;
                }
            } elsif ((($k+3) < $len)&&($txt =~ /\$\w+/)) {
                # skip some big things seen, that are NOT missing macros
                # not really that size matters - if ( ($len > 100) && skip_these_strings($txt) ) {
                if ( skip_these_strings($txt) ) {
                    # like skip these [-@(for i in $(srcdir)/test/HTML/* ; do n...], etc
                } else {
                    prtw("[13] WARNING: Potential MACRO [$txt]($len) of form \$MAC NOT HANDLED.\n") if ($dbg_s13);
                }
            }
        } elsif ($ch eq '@') {
            $k = $i + 1;
            if ((($k+1) < $len) && (substr($txt,$k) =~ /^(\w+)\@/)) {
                $mac = '@';
                for (; $k < $len; $k++) {
                    $nc = substr($txt,$k,1);
                    $mac .= $nc;
                    last if ($nc eq '@');
                    last if ($nc =~ /\W/);
                }
                if ($nc eq '@') {
                    push(@arr,$tag) if (length($tag) && $add);
                    $tag = '';
                    push(@arr,$mac);
                    $ch = '';
                    $i = $k;
                }
            }
        }
        if ($add && (($ch eq "'") || ($ch eq '"'))) {
            push(@arr,$tag) if (length($tag) && $add);
            $tag = '';
            push(@arr,$ch);
        } else {
            $tag .= $ch;
        }
    }
    return @arr;
}

sub valid_for_am_test($) {
    my ($rparams) = @_;
    my @arr = qw(CURR_LINE CURR_REF_HASH CURR_LINENUM AM_FILE CURR_COMMON_SUBS CURR_COMMON_SUBS
        CURR_USER_SUBS CURR_SUBS_NOT_FOUND);
    my ($key);
    foreach $key (@arr) {
        if (!defined ${$rparams}{$key}) {
            my $line = __LINE__;
            my $file = __FILE__;
            pgm_exit(1,"Service 'am_test_for_substitution' call in module [$file]\n".
                " around line $line, with key [$key] NOT DEFINED!\n");
        }
    }

}

sub show_scalar_hash($) {
    my ($rh) = @_;
    my ($cnt,$key,$val);
    $cnt = 0;
    foreach $key (keys %{$rh}) {
        $val = ${$rh}{$key};
        $cnt++;
        prt(" $cnt: [$key] = [$val]\n");
    }
}

sub show_all_subs($$) {
    my ($key,$rparams) = @_;
    my ($cnt);
    prt("Searching for [$key]\n");
    my $rus  = ${$rparams}{'CURR_USER_SUBS'};
    $cnt = scalar keys(%{$rus});
    prt("Got $cnt USER subs...\n");
    show_scalar_hash($rus);
    my $rhash = ${$rparams}{'CURR_REF_HASH'};
    $cnt = scalar keys(%{$rhash});
    prt("Got $cnt RTHASH subs...\n");
    show_scalar_hash($rhash);
    my $rcomsubs = ${$rparams}{'CURR_COMMON_SUBS'};
    $cnt = scalar keys(%{$rcomsubs});
    prt("Got $cnt COMMON subs...\n");
    show_scalar_hash($rcomsubs);
    pgm_exit(1,"ERROR: $key should be one of those!!!!\n");
}

sub key_in_cond_TRUE($$$) {
    my ($key,$rhash,$rval) = @_;
    my ($tmp);
    foreach $tmp (keys %{$rhash}) {
        if ($tmp =~ /^$key\s+.+\@_TRUE\@/) {
            ${$rval} = $tmp;
            return 1;
        }
    }
    return 0;
}
sub key_in_cond_FALSE($$$) {
    my ($key,$rhash,$rval) = @_;
    my ($tmp);
    foreach $tmp (keys %{$rhash}) {
        if ($tmp =~ /^$key\s+.+\@_FALSE\@/) {
            ${$rval} = $tmp;
            return 2;
        }
    }
    return 0;
}

sub key_in_cond_TRUE_or_FALSE($$$) {
    my ($key,$rhash,$rkey) = @_;
    my $ret = 0;
    my $valT = '';
    my $valF = '';
    my @nkeys = ();
    $ret |= 1 if (key_in_cond_TRUE($key,$rhash,\$valT));
    $ret |= 2 if (key_in_cond_FALSE($key,$rhash,\$valF));
    if (($ret & 1)&&(length($valT))) {
        push(@nkeys,$valT);
    }
    if (($ret & 2)&&(length($valF))&&($valF ne $valT)) {
        push(@nkeys,$valF);
    }
    ${$rkey} = \@nkeys;
    return $ret;
}


sub key_in_a_conditional($$$$) {
    my ($key,$rhash,$rparams,$rtmp) = @_;
    # 27/09/2010 - user conditionals
    my $rusrcond = ${$rparams}{'REF_DEF_CONDITIONS'};
    my $auto_on  = ${$rparams}{'CURR_AUTO_ON_FLAG'};  # = $auto_on_flag;
    my ($tmp,$cond,$val,$tf,$prev,$k1,$k2,$v2,$msg,$cnt,$res,$user);
    $prev = key_in_cond_TRUE($key,$rhash,\$k2);
    $v2 = ($prev ? ${$rhash}{$k2} : '');
    $val = '';
    $tf = 'TRUE';
    $cnt = 0;
    $res = '';
    foreach $tmp (keys %{$rhash}) {
        if ($tmp =~ /^$key\s+if\s+(\w+)\@_(TRUE|FALSE)\@/) {
            $k1 = $1;
            $cond = $2;
            $cnt++;
            $val = ${$rhash}{$tmp};
            $tf = 'TRUE';
            $msg = 'Assumed';
            $user = 0;
            if (defined ${$rusrcond}{$k1}) {
                $tf = ${$rusrcond}{$k1};
                $msg = 'as SET by user';
                $user = 1;
            }
            if ($cond eq $tf) {
                ${$rtmp} = $tmp;
                if ($prev) {
                    if ($val ne $v2) {
                        prt("[22] CHANGED:1: [$tmp] key [$key] cond [$cond] Was [$v2], now [$val] $tf $msg\n") if ($dbg_s22);
                    } else {
                        prt("[22] NOCHANGE:1: [$tmp] key [$key] cond [$cond] stays [$val] $tf $msg\n") if ($dbg_s22);
                    }
                } else {
                    prt("[22] CHANGED:2: [$tmp] key [$key] cond [$cond] Was [$v2] NOTHING, now [$val] $tf $msg\n") if ($dbg_s22);
                }
                return 1;
            } elsif (($user == 0) && ($auto_on & 1024)) {
                ${$rtmp} = $tmp;
                $msg .= ', auto-bit=1024';
                if ($prev) {
                    if ($val ne $v2) {
                        prt("[22] CHANGED:6: [$tmp] key [$key] cond [$cond] Was [$v2], now [$val] $tf $msg\n") if ($dbg_s22);
                    } else {
                        prt("[22] NOCHANGE:6: [$tmp] key [$key] cond [$cond] stays [$val] $tf $msg\n") if ($dbg_s22);
                    }
                } else {
                    prt("[22] CHANGED:7: [$tmp] key [$key] cond [$cond] Was [$v2] NOTHING, now [$val] $tf $msg\n") if ($dbg_s22);
                }
                return 1;
            }
            $res .= " + " if (length($res));
            $res .= "[$k1] [$val] [$cond] ne [$tf]";
        }
    }
    if ($cnt) {
        # found a key or 2 that matched
        prt("[22] MISSED CHANGE:5: FOUND $cnt key [$key], BUT $res!\n") if ($dbg_s22);
        return 0;
    }
    if ($prev) {
        prt("[22] MISSED CHANGE:3: key [$key] [$k2] Was [$v2], now NOT FOUND!\n") if ($dbg_s22);
    } else {
        prt("[22] MISSED CHANGE:4: key [$key] NOT FOUND!\n") if ($dbg_s22);
        # special
#        if ($key eq 'PRINTF_SUBDIR') {
#            prt("Additional: HOW COME THIS NOT FOUND? List of keys...\n");
#            foreach $tmp (keys %{$rhash}) {
#                if ($tmp =~ /^(\w+)\s+if\s+(\w+)\@_(TRUE|FALSE)\@$/) {
#                    $v2 = $1;
#                    $val = $2;
#                    $tf = $3;
#                    prt(" Cond: [$v2] if [$val] [$tf]\n");
#                } else {
#                    prt(" Key: $tmp\n");
#                }
#            }
#        }
    }
    return 0;
}

#sub test_for_substitution($$$$) {
#    my ($line,$rhash,$i2,$sfil) = @_;
# 09/09/2010 - also try to EXPAND @ABC@ macros
# 1: $(MACRO)
# 2: ${MACRO}
# 3: @MACRO@
# found : 1=rhash, 2=rhash mod, 3=common, 4=User
# WHY [13|14] 28:1: NO sub FOUND for [$(PRINTF_SUBDIR)] key [PRINTF_SUBDIR]  file [glib\Makefile.am]
# WHEN [12] 6: Setting key [PRINTF_SUBDIR if HAVE_GOOD_PRINTF@_FALSE@], with value [gnulib] typ 1
# CAUSING: WARNING:1: Substitution DONE [PRINTF_SUBDIR] to [gnulib]. [1] WHY WAS THIS NOT DONE EARLIER?
sub am_test_for_substitution($) {
    my ($rparams) = @_;
    #valid_for_am_test($rparams);
    my $line = ${$rparams}{'CURR_LINE'};
    if (($line =~ /\$/)||($line =~ /\@\w+\@/)) {
        my $rhash = ${$rparams}{'CURR_REF_HASH'};
        my $i2 = ${$rparams}{'CURR_LINENUM'};
        my $fil = ${$rparams}{'AM_FILE'};
        #my $rcomsubs = ${$rparams}{'REF_COMMON_SUBS'};
        my $rcomsubs = ${$rparams}{'CURR_COMMON_SUBS'};
        my $rus  = ${$rparams}{'CURR_USER_SUBS'};
        my $rsnf = ${$rparams}{'CURR_SUBS_NOT_FOUND'};
        my $rglobhash = ${$rparams}{'REF_GLOBAL_HASH'};
        my $sfil = sub_root_folder($fil);
        my $oline = $line; # keep copy of original
        my @item_arr = am_macro_split($line,0);
        my ($item,$key,$nval,$tmp,$done,$cnt,$typ,$fnd,$dncnt,$totcnt);
        $totcnt = scalar @item_arr;
        prt("[13] am macro split to $totcnt items [$line]\n") if ($dbg_s13);
        $cnt = 0;
        $fnd = 0;
        my @subs = ();
        foreach $item (@item_arr) {
            $dncnt++;
            prt("[13] $dncnt of $totcnt: item [$item]\n") if ($dbg_s13);
            $typ = 0;
            if ($item =~ /^\$\((\w+)\)$/) {
                $key = $1;
                $done = 0;
                $typ = 1;    # is of form $(MACRO)
                if (defined ${$rus}{$key}) {
                    $nval = ${$rus}{$key};
                    $line =~ s/\$\($key\)/$nval/;
                    $fnd = 4;
                    prt("[13] $i2:$typ:$fnd: Did sub of [$key] to [$nval]\n") if ($dbg_s13);
                    push(@subs,"$i2:$typ:$fnd:$item:$key:$nval");
                    $done = 1;
                    $cnt++;
                } elsif (defined ${$rcomsubs}{$key}) {
                    # try in the common, which can be user expanded
                    $nval = ${$rcomsubs}{$key};
                    $line =~ s/\$\($key\)/$nval/;
                    $fnd = 3;
                    prt("[13] $i2:$typ:$fnd: Did sub to [$nval] key [$key] common subs\n") if ($dbg_s13);
                    push(@subs,"$i2:$typ:$fnd:$item:$key:$nval");
                    $done = 1;
                    $cnt++;
                } elsif (defined ${$rglobhash}{$key}) {
                    $nval = ${$rglobhash}{$key};
                    $line =~ s/\$\($key\)/$nval/;
                    $fnd = 5;
                    prt("[13] $i2:$typ:$fnd: Did sub to [$nval] key [$key] common subs\n") if ($dbg_s13);
                    push(@subs,"$i2:$typ:$fnd:$item:$key:$nval");
                    $done = 1;
                    $cnt++;
                } elsif (defined ${$rhash}{$key}) {
                    $nval = ${$rhash}{$key};
                    $line =~ s/\$\($key\)/$nval/;
                    $fnd = 1;
                    prt("[13] $i2:$typ:$fnd: Did sub of [$key] to [$nval]\n") if ($dbg_s13);
                    push(@subs,"$i2:$typ:$fnd:$item:$key:$nval");
                    $done = 1;
                    $cnt++;
                } elsif ( key_in_a_conditional($key,$rhash,$rparams,\$tmp) ) {
                    #foreach $tmp (keys %{$rhash}) {
                    #    if ($tmp =~ /^$key\s+.+\@_TRUE\@/) {
                            $nval = ${$rhash}{$tmp};
                            $line =~ s/\$\($key\)/$nval/;
                            $fnd = 2;
                            prt("[13] $i2:$typ:$fnd: Did sub to [$nval] key [$key] tmp = [$tmp]\n") if ($dbg_s13);
                            push(@subs,"$i2:$typ:$fnd:$item:$key:$nval");
                            $done = 1;
                            $cnt++;
                    #    }
                }
                if (!$done) {
                    prt("[13|14] $i2:$typ: NO sub FOUND for [$item] key [$key]  file [$sfil]\n") if ($dbg_s13 || $dbg_s14);
                    #$subs_not_found{$key} = $sfil;
                    if (! defined ${$rsnf}{$key}) {
                        ${$rsnf}{$key} = "$i2:$sfil";
                    }
                }
            } elsif ($item =~ /^\$\{(\w+)\}$/) {
                $key = $1;
                $done = 0;
                $typ = 2;    # is of form ${MACRO}
                if (defined ${$rus}{$key}) {
                    $nval = ${$rus}{$key};
                    $line =~ s/\$\{$key\}/$nval/;
                    $fnd = 4;
                    prt("[13] $i2:$typ:$fnd: Did sub of [$key] to [$nval]\n") if ($dbg_s13);
                    push(@subs,"$i2:$typ:$fnd:$item:$key:$nval");
                    $done = 1;
                    $cnt++;
                } elsif (defined ${$rcomsubs}{$key}) {
                    $nval = ${$rcomsubs}{$key};
                    $line =~ s/\$\{$key\}/$nval/;
                    $fnd = 3;
                    prt("[13] $i2:$typ:$fnd: Did sub to [$nval] key [$key] common subs\n") if ($dbg_s13);
                    push(@subs,"$i2:$typ:$fnd:$item:$key:$nval");
                    $done = 1;
                    $cnt++;
                } elsif (defined ${$rglobhash}{$key}) {
                    # try global (known) items
                    $nval = ${$rglobhash}{$key};
                    $line =~ s/\$\{$key\}/$nval/;
                    $fnd = 5;
                    prt("[13] $i2:$typ:$fnd: Did sub to [$nval] key [$key] common subs\n") if ($dbg_s13);
                    push(@subs,"$i2:$typ:$fnd:$item:$key:$nval");
                    $done = 1;
                    $cnt++;
                } elsif (defined ${$rhash}{$key}) {
                    $nval = ${$rhash}{$key};
                    $line =~ s/\$\{$key\}/$nval/;
                    $fnd = 1;
                    prt("[13] $i2:$typ:$fnd: Did sub of [$key] to [$nval]\n") if ($dbg_s13);
                    push(@subs,"$i2:$typ:$fnd:$item:$key:$nval");
                    $done = 1;
                    $cnt++;
                } elsif ( key_in_a_conditional($key,$rhash,$rparams,\$tmp) ) {
                    #foreach $tmp (keys %{$rhash}) {
                    #    if ($tmp =~ /^$key\s+.+\@_TRUE\@/) {
                            $nval = ${$rhash}{$tmp};
                            $line =~ s/\$\{$key\}/$nval/;
                            $fnd = 2;
                            prt("[13] $i2:$typ:$fnd: Did sub to [$nval] key [$key] tmp = [$tmp]\n") if ($dbg_s13);
                            push(@subs,"$i2:$typ:$fnd:$item:$key:$nval");
                            $done = 1;
                            $cnt++;
                    #    }
                }
                if (!$done) {
                    prt("[13|14] $i2:$typ: NO sub FOUND for [$item] key [$key]  file [$sfil]\n") if ($dbg_s13 || $dbg_s14);
                    #$subs_not_found{$key} = $sfil;
                    if (! defined ${$rsnf}{$key}) {
                        ${$rsnf}{$key} = "$i2:$sfil";
                    }
                }
            } elsif ($item =~ /^\@(\w+)\@$/) {
                $key = $1;
                $done = 0;
                $typ = 3;   # is of the form @MACRO@
                if (defined ${$rus}{$key}) {
                    $nval = ${$rus}{$key};
                    $line =~ s/\@$key\@/$nval/;
                    $fnd = 4;
                    prt("[13] $i2:$typ:$fnd: Did sub of [$key] to [$nval]\n") if ($dbg_s13);
                    push(@subs,"$i2:$typ:$fnd:$item:$key:$nval");
                    $done = 1;
                    $cnt++;
                } elsif (defined ${$rcomsubs}{$key}) {
                    # try in the common, which can be user expanded
                    $nval = ${$rcomsubs}{$key};
                    $line =~ s/\@$key\@/$nval/;
                    $fnd = 3;
                    prt("[13] $i2:$typ:$fnd: Did sub to [$nval] key [$key] common subs\n") if ($dbg_s13);
                    push(@subs,"$i2:$typ:$fnd:$item:$key:$nval");
                    $done = 1;
                    $cnt++;
                } elsif (defined ${$rglobhash}{$key}) {
                    # try global (known) items
                    $nval = ${$rglobhash}{$key};
                    $line =~ s/\@$key\@/$nval/;
                    $fnd = 5;
                    prt("[13] $i2:$typ:$fnd: Did sub to [$nval] key [$key] common subs\n") if ($dbg_s13);
                    push(@subs,"$i2:$typ:$fnd:$item:$key:$nval");
                    $done = 1;
                    $cnt++;
                } elsif (defined ${$rhash}{$key}) {
                    $nval = ${$rhash}{$key};
                    $line =~ s/\@$key\@/$nval/;
                    $fnd = 1;
                    prt("[13] $i2:$typ:$fnd: Did sub of [$key] to [$nval]\n") if ($dbg_s13);
                    push(@subs,"$i2:$typ:$fnd:$item:$key:$nval");
                    $done = 1;
                    $cnt++;
                } elsif ( key_in_a_conditional($key,$rhash,$rparams,\$tmp) ) {
                    #foreach $tmp (keys %{$rhash}) {
                    #    if ($tmp =~ /^$key\s+.+\@_TRUE\@/) {
                            $nval = ${$rhash}{$tmp};
                            $line =~ s/\@$key\@/$nval/;
                            $fnd = 2;
                            prt("[13] $i2:$typ:$fnd: Did sub to [$nval] key [$key] tmp = [$tmp]\n") if ($dbg_s13);
                            push(@subs,"$i2:$typ:$fnd:$item:$key:$nval");
                            $done = 1;
                            $cnt++;
                    #    }
                }
                if (!$done) {
                    #$subs_not_found{$key} = $sfil;
                    prt("[13|14] $i2:$typ: NO sub FOUND for [$item] key [$key]  file [$sfil]\n") if ($dbg_s13 || $dbg_s14);
                    if (! defined ${$rsnf}{$key}) {
                        # keep only the FIRST instance
                        ${$rsnf}{$key} = "$i2:$sfil";
                    }
                    ##### show_all_subs($key,$rparams);
                }
            } else {
                prtw("WARNING: am_test_for_substitution: got a split NOT handled! [$item]\n");
            }
        } # for each item

        # ================================================
        # done all items
        if ($line ne $oline) {
            prt("[13] $i2: Line SUB [$oline] TO [$line]\n") if ($dbg_s13);
        } elsif ($cnt) {
			# 20120311 - downgrade to a WARNING
            # $nval = "ERROR INTERNAL: $i2:$cnt: SUBSTITUTIONS FAILED! file [$sfil]\n";
            $nval = "WARNING: $i2:$cnt: SUBSTITUTIONS FAILED! file [$sfil]\n";
            $fnd = length($oline);
            $cnt = length($line);
            $nval .= "Appears SUB failed to CHANGE LINE!\n orig [$oline]$fnd\n curr [$line]$cnt\n";
            $cnt = 0;
            foreach my $itm (@subs) {
                $cnt++;
                $nval .= " $cnt: [$item]\n";
            }
            #pgm_exit(1,"$nval\n");
            prtw("$nval\n");
        }
    }
    return $line;
}

sub am_test_for_substitution_VERY_OK_BUT($) {
    my ($rparams) = @_;
    valid_for_am_test($rparams);
    my $line = ${$rparams}{'CURR_LINE'};
    if (($line =~ /\$/)||($line =~ /\@\w+\@/)) {
        my $rhash = ${$rparams}{'CURR_REF_HASH'};
        my $i2 = ${$rparams}{'CURR_LINENUM'};
        my $fil = ${$rparams}{'AM_FILE'};
        #my $rcomsubs = ${$rparams}{'REF_COMMON_SUBS'};
        my $rcomsubs = ${$rparams}{'CURR_COMMON_SUBS'};
        my $rus  = ${$rparams}{'CURR_USER_SUBS'};
        my $rsnf = ${$rparams}{'CURR_SUBS_NOT_FOUND'};
        my $rglobhash = ${$rparams}{'REF_GLOBAL_HASH'};
        my $sfil = sub_root_folder($fil);
        my $oline = $line; # keep copy of original
        my @arr = am_macro_split($line,0);
        my ($itm,$key,$nval,$tmp,$done,$cnt,$typ,$fnd);
        $cnt = 0;
        $fnd = 0;
        my @subs = ();
        foreach $itm (@arr) {
            $typ = 0;
            if ($itm =~ /^\$\((\w+)\)$/) {
                $key = $1;
                $done = 0;
                $typ = 1;    # is of form $(MACRO)
                if (defined ${$rus}{$key}) {
                    $nval = ${$rus}{$key};
                    $line =~ s/\$\($key\)/$nval/;
                    $fnd = 4;
                    prt("[13] $i2:$typ:$fnd: Did sub of [$key] to [$nval]\n") if ($dbg_s13);
                    push(@subs,"$i2:$typ:$fnd:$itm:$key:$nval");
                    $done = 1;
                    $cnt++;
                } elsif (defined ${$rhash}{$key}) {
                    $nval = ${$rhash}{$key};
                    $line =~ s/\$\($key\)/$nval/;
                    $fnd = 1;
                    prt("[13] $i2:$typ:$fnd: Did sub of [$key] to [$nval]\n") if ($dbg_s13);
                    push(@subs,"$i2:$typ:$fnd:$itm:$key:$nval");
                    $done = 1;
                    $cnt++;
                } else {
                    if ( key_in_a_conditional($key,$rhash,$rparams,\$tmp) ) {
                    #foreach $tmp (keys %{$rhash}) {
                    #    if ($tmp =~ /^$key\s+.+\@_TRUE\@/) {
                            $nval = ${$rhash}{$tmp};
                            $line =~ s/\$\($key\)/$nval/;
                            $fnd = 2;
                            prt("[13] $i2:$typ:$fnd: Did sub to [$nval] key [$key] tmp = [$tmp]\n") if ($dbg_s13);
                            push(@subs,"$i2:$typ:$fnd:$itm:$key:$nval");
                            $done = 1;
                            $cnt++;
                            last;
                    #    }
                    }
                }
                if (!$done) {
                    # try in the common, which can be user expanded
                    if (defined ${$rcomsubs}{$key}) {
                        $nval = ${$rcomsubs}{$key};
                        $line =~ s/\$\($key\)/$nval/;
                        $fnd = 3;
                        prt("[13] $i2:$typ:$fnd: Did sub to [$nval] key [$key] common subs\n") if ($dbg_s13);
                        push(@subs,"$i2:$typ:$fnd:$itm:$key:$nval");
                        $done = 1;
                        $cnt++;
                    }
                    if (!$done) {
                        if (defined ${$rglobhash}{$key}) {
                            $nval = ${$rglobhash}{$key};
                            $line =~ s/\$\($key\)/$nval/;
                            $fnd = 5;
                            prt("[13] $i2:$typ:$fnd: Did sub to [$nval] key [$key] common subs\n") if ($dbg_s13);
                            push(@subs,"$i2:$typ:$fnd:$itm:$key:$nval");
                            $done = 1;
                            $cnt++;
                        }
                    }
                }

                if (!$done) {
                    prt("[13|14] $i2:$typ: NO sub FOUND for [$itm] key [$key]  file [$sfil]\n") if ($dbg_s13 || $dbg_s14);
                    #$subs_not_found{$key} = $sfil;
                    if (! defined ${$rsnf}{$key}) {
                        ${$rsnf}{$key} = "$i2:$sfil";
                    }
                }
            } elsif ($itm =~ /^\$\{(\w+)\}$/) {
                $key = $1;
                $done = 0;
                $typ = 2;    # is of form ${MACRO}
                if (defined ${$rus}{$key}) {
                    $nval = ${$rus}{$key};
                    $line =~ s/\$\{$key\}/$nval/;
                    $fnd = 4;
                    prt("[13] $i2:$typ:$fnd: Did sub of [$key] to [$nval]\n") if ($dbg_s13);
                    push(@subs,"$i2:$typ:$fnd:$itm:$key:$nval");
                    $done = 1;
                    $cnt++;
                } elsif (defined ${$rhash}{$key}) {
                    $nval = ${$rhash}{$key};
                    $line =~ s/\$\{$key\}/$nval/;
                    $fnd = 1;
                    prt("[13] $i2:$typ:$fnd: Did sub of [$key] to [$nval]\n") if ($dbg_s13);
                    push(@subs,"$i2:$typ:$fnd:$itm:$key:$nval");
                    $done = 1;
                    $cnt++;
                } else {
                    if ( key_in_a_conditional($key,$rhash,$rparams,\$tmp) ) {
                    #foreach $tmp (keys %{$rhash}) {
                    #    if ($tmp =~ /^$key\s+.+\@_TRUE\@/) {
                            $nval = ${$rhash}{$tmp};
                            $line =~ s/\$\{$key\}/$nval/;
                            $fnd = 2;
                            prt("[13] $i2:$typ:$fnd: Did sub to [$nval] key [$key] tmp = [$tmp]\n") if ($dbg_s13);
                            push(@subs,"$i2:$typ:$fnd:$itm:$key:$nval");
                            $done = 1;
                            $cnt++;
                            last;
                    #    }
                    }
                }
                if (!$done) {
                    # try in the common, which can be user expanded
                    if (defined ${$rcomsubs}{$key}) {
                        $nval = ${$rcomsubs}{$key};
                        $line =~ s/\$\{$key\}/$nval/;
                        $fnd = 3;
                        prt("[13] $i2:$typ:$fnd: Did sub to [$nval] key [$key] common subs\n") if ($dbg_s13);
                        push(@subs,"$i2:$typ:$fnd:$itm:$key:$nval");
                        $done = 1;
                        $cnt++;
                    }
                    if (!$done) {
                        # try global (known) items
                        if (defined ${$rglobhash}{$key}) {
                            $nval = ${$rglobhash}{$key};
                            $line =~ s/\$\{$key\}/$nval/;
                            $fnd = 5;
                            prt("[13] $i2:$typ:$fnd: Did sub to [$nval] key [$key] common subs\n") if ($dbg_s13);
                            push(@subs,"$i2:$typ:$fnd:$itm:$key:$nval");
                            $done = 1;
                            $cnt++;
                        }
                    }
                }
                if (!$done) {
                    prt("[13|14] $i2:$typ: NO sub FOUND for [$itm] key [$key]  file [$sfil]\n") if ($dbg_s13 || $dbg_s14);
                    #$subs_not_found{$key} = $sfil;
                    if (! defined ${$rsnf}{$key}) {
                        ${$rsnf}{$key} = "$i2:$sfil";
                    }
                }
            } elsif ($itm =~ /^\@(\w+)\@$/) {
                $key = $1;
                $done = 0;
                $typ = 3;   # is of the form @MACRO@
                if (defined ${$rus}{$key}) {
                    $nval = ${$rus}{$key};
                    $line =~ s/\@$key\@/$nval/;
                    $fnd = 4;
                    prt("[13] $i2:$typ:$fnd: Did sub of [$key] to [$nval]\n") if ($dbg_s13);
                    push(@subs,"$i2:$typ:$fnd:$itm:$key:$nval");
                    $done = 1;
                    $cnt++;
                } elsif (defined ${$rhash}{$key}) {
                    $nval = ${$rhash}{$key};
                    $line =~ s/\@$key\@/$nval/;
                    $fnd = 1;
                    prt("[13] $i2:$typ:$fnd: Did sub of [$key] to [$nval]\n") if ($dbg_s13);
                    push(@subs,"$i2:$typ:$fnd:$itm:$key:$nval");
                    $done = 1;
                    $cnt++;
                } else {
                    if ( key_in_a_conditional($key,$rhash,$rparams,\$tmp) ) {
                    #foreach $tmp (keys %{$rhash}) {
                    #    if ($tmp =~ /^$key\s+.+\@_TRUE\@/) {
                            $nval = ${$rhash}{$tmp};
                            $line =~ s/\@$key\@/$nval/;
                            $fnd = 2;
                            prt("[13] $i2:$typ:$fnd: Did sub to [$nval] key [$key] tmp = [$tmp]\n") if ($dbg_s13);
                            push(@subs,"$i2:$typ:$fnd:$itm:$key:$nval");
                            $done = 1;
                            $cnt++;
                            last;
                    #    }
                    }
                }
                if (!$done) {
                    # try in the common, which can be user expanded
                    if (defined ${$rcomsubs}{$key}) {
                        $nval = ${$rcomsubs}{$key};
                        $line =~ s/\@$key\@/$nval/;
                        $fnd = 3;
                        prt("[13] $i2:$typ:$fnd: Did sub to [$nval] key [$key] common subs\n") if ($dbg_s13);
                        push(@subs,"$i2:$typ:$fnd:$itm:$key:$nval");
                        $done = 1;
                        $cnt++;
                    }
                    if (!$done) {
                        # try global (known) items
                        if (defined ${$rglobhash}{$key}) {
                            $nval = ${$rglobhash}{$key};
                            $line =~ s/\@$key\@/$nval/;
                            $fnd = 5;
                            prt("[13] $i2:$typ:$fnd: Did sub to [$nval] key [$key] common subs\n") if ($dbg_s13);
                            push(@subs,"$i2:$typ:$fnd:$itm:$key:$nval");
                            $done = 1;
                            $cnt++;
                        }
                    }
                }

                if (!$done) {
                    #$subs_not_found{$key} = $sfil;
                    prt("[13|14] $i2:$typ: NO sub FOUND for [$itm] key [$key]  file [$sfil]\n") if ($dbg_s13 || $dbg_s14);
                    if (! defined ${$rsnf}{$key}) {
                        # keep only the FIRST instance
                        ${$rsnf}{$key} = "$i2:$sfil";
                    }
                    ##### show_all_subs($key,$rparams);
                }
            } else {
                prtw("WARNING: am_test_for_substitution: got a split NOT handled! [$itm]\n");
            }
        }
        if ($line ne $oline) {
            prt("[13] $i2: Line SUB [$oline] TO [$line]\n") if ($dbg_s13);
        } elsif ($cnt) {
			# 20120311 - downgrade to a WARNING
            # $nval = "ERROR INTERNAL: $i2:$cnt: SUBSTITUTIONS FAILED! file [$sfil]\n";
            $nval = "WARNING: $i2:$cnt: SUBSTITUTIONS FAILED! file [$sfil]\n";
            $fnd = length($oline);
            $cnt = length($line);
            $nval .= "Appears SUB failed to CHANGE LINE!\n orig [$oline]$fnd\n curr [$line]$cnt\n";
            $cnt = 0;
            foreach $itm (@subs) {
                $cnt++;
                $nval .= " $cnt: [$itm]\n";
            }
            # pgm_exit(1,"$nval\n");
			prtw("$nval\n");
        }
    }
    return $line;
}

########################################################
# given two scalar items, separated by '\s' or '\'
# reutrn ZERO if ALL the second are IN the first.
sub value_not_in_first($$) {
    my ($src,$rval) = @_;    # $programs{$ky},$val
    my @arr1 = split(/[\s\|]/,$src);
    my $val2 = ${$rval};
    my @arr2 = split(/[\s\|]/,$val2);
    my $cnt = scalar @arr2;
    my ($val1,$dcnt);
    if ($cnt == 1) {
        foreach $val1 (@arr1) {
            return 0 if ($val1 eq $val2);
        }
    } else {
        # put values in a hash, to allow delete
        my %vals = ();
        foreach $val1 (@arr2) {
            $vals{$val1} = 1;
        }
        $dcnt = 0;
        foreach $val1 (@arr1) {
            if (defined $vals{$val1}) {
                delete $vals{$val1};
                $dcnt++;
            }
        }
        if ($dcnt) {
            @arr1 = keys(%vals);
            return 0 if (scalar @arr1 == 0);
            # but if there were 'some' items delete due to existance
            # then adjust the original $val...
            ${$rval} = join(' ',@arr1);
        }
    }
    return 1;
}

sub get_value_from_hash {
    my ($rval2,$ms,$rhash,$rparams) = @_;
    my ($ky2, @vals, $fnd, $val, @keys, $i);
    my ($itm, $cond);
    my $rdef_conds = ${$rparams}{'REF_DEF_CONDITIONS'};

    $fnd = 0;

    foreach $ky2 (keys %{$rhash}) {
        if ($ky2 =~ /^$ms\s+/) {
            $val = ${$rhash}{$ky2};
            if (!is_in_array($val, @vals)) {
                push(@vals,$val);
                push(@keys,$ky2);
                $fnd++;
            }
        }
    }
    if ($fnd == 1) {
        $$rval2 = $vals[0]; # just ONE to RETURN
    } elsif ($fnd > 1) {
        my $msg = "WARNING: For sub of [$ms], have [$fnd] to CHOOSE FROM!\n";
        for ($i = 0; $i < $fnd; $i++) {
            $val = $vals[$i];
            $ky2 = $keys[$i];
            $msg .= " or \n" if ($i > 0);
            $msg .= "[$ky2={".$val.'}]';
            if ($ky2 =~ /^$ms\s+if\s+(\w+)\@_(TRUE|FALSE)\@/) {
                $itm = $1;
                $cond = $2;
                $msg .= " [$itm]=[$cond]";
                if (defined ${$rdef_conds}{$itm}) {
                    if (${$rdef_conds}{$itm} eq $cond) {
                        $$rval2 = $val; # RETURN selected
                        ### prtw("CHECK: Returning [$val] for [$ms], due [$itm]=[$cond] in def_condits!\n" );
                        return $fnd;
                    }
                }
            }
        }
        $msg .= " Defaulting to FIRST! CHECK ME!!";
        prtw("$msg\n");
        ${$rval2} = $vals[0]; # just RETURN first
    }
    return $fnd;
}

# did, one or more AM (or IN) files, but NO libraries, or programs
# my $ref_targets = ${$rparams}{'AM_FILE_TARGETS'};
sub show_target_list($) {
    my ($rparams) = @_;
    my $ref_targets = ${$rparams}{'AM_FILE_TARGETS'};
    my ($cnt,$key,$fcnt,$scnt,$val);
    $cnt = scalar keys(%{$ref_targets});
    $fcnt = 0;
    prt("\[21] nGot NO libraries, or programs, checking $cnt 'targets'...\n");
    foreach $key (keys %{$ref_targets}) {
        if ($key =~ /^\w+$/) {
            $fcnt++;
            $val = ${$ref_targets}{$key};
            prt(" $fcnt: [$key] = [$val]\n");
        }
    }
    prt("\nOther targets...\n");
    $scnt = 0;
    foreach $key (keys %{$ref_targets}) {
        if ( !($key =~ /^\w+$/) ) {
            $scnt++;
            $val = ${$ref_targets}{$key};
            prt(" $scnt: [$key] = [$val]\n");
        }
    }
    prt("[21] Done $cnt targets list... got $fcnt as alphanumeric, and others $scnt...\n");
}

# ========================================================================================
# process_target_list
# Present assumtions
# - The process starts with finding 'all', or if not 'default' targets
#   and assumes its contents (after expansion) are the final 'targets' desired.
#   results stored in %objects = $value hash.
# - Each 'target' is then searched, and results found are stored in %sobjects = $value hash
# - Libraries are assumed to end in '.la', else assumed a console application
# - Only C and H files are stored
# =========================================================================================
sub process_target_list($) {
    my ($rparams) = @_;
    # if it is an Makefile.in, then may have to look at TARGETS for libraries/programs/sources
    show_target_list($rparams) if ($dbg_s21);
    my $ref_targets = ${$rparams}{'AM_FILE_TARGETS'};
    my ($cnt,$key,$fcnt,$scnt,$val,@arr,$dkey,$dval,$ky,$v,%dupes);
    my ($kyo,@arr2,$itm,$nv);
    $cnt = scalar keys(%{$ref_targets});
    prt("\n[21] Seeking 'all' or 'default' in $cnt keys...\n") if ($dbg_s21 || VERB9());
    $fcnt = 0;
    $val = '';
    $dkey = '';
    $dval = '';
    foreach $key (keys %{$ref_targets}) {
        if ($key =~ /^all$/) {
            $val = ${$ref_targets}{$key};
            prt(" [$key] = [$val]\n") if ($dbg_s21);
            if ( length($val) && !($val =~ /^\s+$/) ) {
                $fcnt++;
                $dkey = $key;
                $dval = $val;
                last;
            }
        }
    }
    if (!$fcnt) {
        foreach $key (keys %{$ref_targets}) {
            if ($key =~ /^default$/) {
                $val = ${$ref_targets}{$key};
                prt(" [$key] = [$val]\n") if ($dbg_s21);
                if ( length($val) && !($val =~ /^\s+$/) ) {
                    $fcnt++;
                    $dkey = $key;
                    $dval = $val;
                    last;
                }
            }
        }
    }
    if ( !$fcnt || (length($dval) == 0) || ($dval =~ /^\s+$/)) {
        prt("[21] Valid target 'all' or 'default' NOT found in $cnt keys... [$dval]\n") if ($dbg_s21);
        return;
    }
    @arr = split(/\s/,$dval); # split to an ARRAY
    %dupes = ();
    $dupes{$dkey} = 1;
    my %objects = ();
    my %sobjects = ();
    my %not_found = ();
    my %dupes2 = ();
    foreach $ky (@arr) {
        next if (defined $dupes{$ky});
        $dupes{$ky} = 1;
        $v = '';
        if (defined ${$ref_targets}{$ky}) {
            $v = ${$ref_targets}{$ky};
        } else {
            foreach $key (keys %{$ref_targets}) {
                next if (defined $dupes{$key});
                if ($key =~ /$ky/) {
                    $v .= ${$ref_targets}{$key};
                }
            }
        }
        if (length($v)) {
            $v =~ s/\n.*$// while ($v =~ /\n/);
            prt("[21] For [$dkey] : [$ky] = [$v]\n") if ($dbg_s21);
            #@arr2 = split(/\s/,$v);
            $objects{$ky} = $v;
        } else {
            if (! defined $not_found{$ky}) {
                $not_found{$ky} = 1;
                prt("[21] Not found [$ky]\n") if ($dbg_s21);
            }
        }
    }
    my %libs = ();
    my $islib = 0;
    # foreach primary object - library or program
    foreach $kyo (keys %objects) {
        $val = $objects{$kyo};
        $islib = ($kyo =~ /\.la$/) ? 1 : 0;
        @arr = split(/\s/,$val);
        # if this is a program, may find a dependence on a LIBRARY
        # in this list...
        foreach $ky (@arr) {
            if (!$islib && ($ky =~ /\.la/)) {
                # a program, seems dependant on a library
                if (defined $libs{$kyo}) {
                    $libs{$kyo} .= " $ky";
                } else {
                    $libs{$kyo} = $ky;
                }
            }
            next if (defined $dupes{$ky});
            $dupes{$ky} = 1;
            $v = '';
            if (defined ${$ref_targets}{$ky}) {
                $v = ${$ref_targets}{$ky};
            } else {
                foreach $key (keys %{$ref_targets}) {
                    next if (defined $dupes{$key});
                    if ($key =~ /$ky/) {
                        $v .= ${$ref_targets}{$key};
                    }
                }
            }
            if (length($v)) {
                $v =~ s/\n.*$// while ($v =~ /\n/);
                #prt("Sub [$kyo] : [$ky] = [$v]\n");
                @arr2 = split(/\s/,$v);
                $nv = '';
                foreach $itm (@arr2) {
                    $itm = sub_root_dir(path_u2d($itm));
                    $itm =~ s/^\\//;
                    if (!defined $dupes2{$itm}) {
                        $dupes2{$itm} = 1;
                        $nv .= ' ' if (length($nv));
                        $nv .= $itm;
                    }
                }
                if (length($nv)) {
                    prt("[21] Red [$kyo] : [$ky] = [$nv]\n") if ($dbg_s21);
                    $sobjects{$ky} = $nv; # if (length($nv))
                } else {
                    prt("[21] Sub [$kyo] : [$ky] = [$v] discarded as duplicates\n") if ($dbg_s21);
                }
            } else {
                if (! defined $not_found{$ky}) {
                    $not_found{$ky} = 1;
                    prt("[21] Not found [$ky]\n") if ($dbg_s21);
                }
            }
        }
    }

    # now to process what was collected
    my $rhash = ${$rparams}{'CURR_REF_HASH'};
    my $r_progs = ${$rparams}{'REF_PROGRAMS'};
    my $r_libs = ${$rparams}{'REF_LIBRARIES'};
    my $srcs = '';
    my $rlh = ${$rparams}{'REF_LIBS_HASH'};
    my $rph = ${$rparams}{'REF_PROG_HASH'};
    # run, just to get built LIBRARY list
#    foreach $key (keys %objects) {
#        $val = $objects{$key};
#        @arr = split(/\s/,$val);
#        %dupes = ();
#        foreach $ky (@arr) {
#            if (defined $sobjects{$ky}) {
#                $v = $sobjects{$ky};
#                @arr2 = split(/\s/,$v);
#                foreach $itm (@arr2) {
#                    if ( is_c_source($itm) ) {
#                        $dupes{$itm} = $key;
#                    }
#                }
#            }
#        }
#        @arr = keys %dupes;
#        $scnt = scalar @arr;
#        if ($scnt) {
#            if ($key =~ /\.la$/) {
#                #$itm = 'LIBRARY';
#                $libs{$key} = 1;
#                prt("Stored [$key] in libs hash, for later dependence addition.\n");
#            }
#        }
#    }
    # now a run to create entries, and include 'libs' in programs
    # by adding it to a LDADD entry in the '$rhash'
    # For [all] : [pcretestexe] = [libpcre.la @POSIX_LIB@ pcretest.obj @ON_WINDOWS@ winshared]
    my $addlibs = '';
    foreach $key (keys %objects) {
        $val = $objects{$key};
        @arr = split(/\s/,$val);
        %dupes = ();
        $addlibs = '';
        foreach $ky (@arr) {
            if (defined $sobjects{$ky}) {
                $v = $sobjects{$ky};
                @arr2 = split(/\s/,$v);
                foreach $itm (@arr2) {
                    if ( is_c_source($itm) ) {
                        $dupes{$itm} = $key;
                    } elsif (defined $libs{$itm}) {
                        $addlibs .= ' ' if (length($addlibs));
                        $addlibs .= $itm;
                    }
                }
            }
        }
        @arr = keys %dupes;
        $scnt = scalar @arr;
        if ($scnt) {
            $srcs = join(" ",@arr);
            if ($key =~ /\.la$/) {
                $itm = 'LIBRARY';
                ${$r_libs}{$key} = [$srcs,$key];
                ${$rlh}{$key} = $rhash; # keep the original Makefile.in hash scan
            } else {
                $itm = 'PROGRAM';
                ${$r_progs}{$key} = [$srcs,$key];
                if (defined $libs{$key}) {
                    $addlibs = $libs{$key};
                    $itm .= " +lib [$addlibs]";
                    if (defined ${$rhash}{'LDADD'}) {
                        ${$rhash}{'LDADD'} .= " $addlibs";
                    } else {
                        ${$rhash}{'LDADD'} = $addlibs;
                    }
                }
                ${$rph}{$key} = $rhash; # keep the original Makefile.in hash scan
            }
            prt("[21] Stored $itm key [$key], with $scnt sources [$srcs]\n") if ($dbg_s21);
        } else {
            prt("[21] Ugh! key [$key], yielded NO sources!\n") if ($dbg_s21);
        }
    }

    prt("[21] Done $cnt targets list...\n") if ($dbg_s21);
}

sub a_source_does_exist($$$) {
    my ($dir,$file,$rval) = @_;
    my ($val,$tmp);
    my @arr = qw( .c .cxx .cpp .cc );
    foreach $val (@arr) {
        $tmp = $file.$val;
        if (-f $dir.$tmp) {
            ${$rval} = $tmp;
            return 1;
        }
    }
    return 0;
}

sub a_source_does_exist_ok($$$) {
    my ($dir,$file,$rval) = @_;
    my ($tmp);
    $tmp = $file.".c";
    if (-f $dir.$tmp) {
        ${$rval} = $tmp;
        return 1;
    }
    $tmp = $file.".cxx";
    if (-f $dir.$tmp) {
        ${$rval} = $tmp;
        return 1;
    }
    $tmp = $file.".cpp";
    if (-f $dir.$tmp) {
        ${$rval} = $tmp;
        return 1;
    }
    $tmp = $file.".cc";
    if (-f $dir.$tmp) {
        ${$rval} = $tmp;
        return 1;
    }
    return 0;
}

# extract info from ONE am file scan,
# and try to do any substitutions, twice, but these should have been done already,
# done at end of each process_AM_file, with the reference hash collected
sub am_extract_from_hash($) {
    my ($rparams) = @_;
    my $am_fil = ${$rparams}{'AM_FILE'}; # active Makefile.am (full path!)

    # store for programs and library SOURCES
    # under the key of the program or library name
    my $r_progs = ${$rparams}{'REF_PROGRAMS'};
    my $r_libs = ${$rparams}{'REF_LIBRARIES'};
    # the actual (messy) Makefile.am HASH
    my $rhash = ${$rparams}{'CURR_REF_HASH'};
    # common substitutions
    #my $rcomsubs = ${$rparams}{'REF_COMMON_SUBS'};
    my $rcomsubs = ${$rparams}{'CURR_COMMON_SUBS'};
    my $rcussubs = ${$rparams}{'CURR_USER_SUBS'};
    my $rglobhash = ${$rparams}{'REF_GLOBAL_HASH'};

    my $rdnf = ${$rparams}{'REF_DEFS_NOT_FOUND'};
    my $rsnf = ${$rparams}{'CURR_SUBS_NOT_FOUND'};
    my $rexcept = ${$rparams}{'REF_SRC_EXCEPT'};

    # reference to the script exit value, should thre be a problem
    my $rexit_val = ${$rparams}{'REF_EXIT_VALUE'};

    # ***TBD*** if it is an Makefile.in, then may have to look at TARGETS for libraries/programs/sources
    my $ref_targets = ${$rparams}{'AM_FILE_TARGETS'};
    # ==================================================================================================
    my ($am_nm, $am_dir) = fileparse($am_fil);    # get am file directory
    my ($key, $val, @av);
    my (@am_rh_skeys, @progs, @progkeys, @libs, @libkeys, @srcs, @srckeys, @psrcs);
    my ($ky, $vky, $ms, $val2, $ky2, $orgval, $fnd, $acnt);
    my ($src, $ff, $scnt, $i, $min, $len, $oky, $fcnt, $tmp);
    my ($tot_scnt,$ok);
    my %dupes = ();
    #my %extract = ();
    # really interested in 
    # noinst_LIBRARIES = libAirports.a
    # noinst_PROGRAMS = calc_loc
    # bin_PROGRAMS = fgfs something
    # libAirports_a_SOURCES = apt_loader.cxx apt_loader.hxx ...
    # 20120528 - Also interested in 'include_HEADERS' - if found, add headers to 
    # source list of the library with greatest sources already, of the program with largest src count
    @am_rh_skeys = sort keys(%{$rhash});
    $acnt = scalar @am_rh_skeys;
    prt( "[02] extract_from_hash: Listing $acnt keys in hash passed... file [$am_fil]\n" ) if ($dbg_s02);
    # collect PROGRAM keys
    @progs = ();
    @progkeys = ();
    @libs = ();
    @libkeys = ();
    @srcs = ();
    @srckeys = ();

    # Try do do ALL substitutions
    # An earlier susbstitution was only by the CONDITION rules,
    # but here, ANY value found is added, whatever the CONDITION
    $min = 0;
    foreach $key (@am_rh_skeys) {
        $val = ${$rhash}{$key};
        $orgval = $val;
        next if (!defined $val || (length($val) == 0));
        if ($val =~ /\$\((\w+)\)/) {
            $ms = $1;
            $val2 = ''; # no sub yet
            $fnd = 0;   # none found
            if (defined ${$rhash}{$ms}) {
                $val2 = ${$rhash}{$ms}; # found in local
                $fnd = 3;
            } elsif (defined ${$rcomsubs}{$ms}) {
                $val2 = ${$rcomsubs}{$ms}; # found in common
                $fnd = 2;
            } elsif (defined ${$rglobhash}{$ms}) {
                $val2 = ${$rglobhash}{$ms};  # found in global
                $fnd = 1;
            } else {
                # hmmm, maybe like 'GFX_CODE if @USE_GLUT_FALSE@ = fg_os_osgviewer.cxx $(GFX_COMMON)'
                $fnd = get_value_from_hash(\$val2, $ms, $rhash, $rparams ); 
            }
            if ($fnd > 0) {
                $val =~ s/\$\($ms\)/$val2/g;
                prt("[02]:1: Substitution DONE [$ms] to [$val2]. [$fnd] IGNORING CONDITIONS!\n") if ($dbg_s02);
            } else {
                # ONLY ON SECOND RUN
                #if ( ! (defined ${$rdnf}{$ms} || defined ${$rsnf}{$ms}) ) {
                #    prtw("[10] WARNING:1: No definition for [$ms] found in hash ...\n" ) if ($dbg_s10);
                #    ${$rdnf}{$ms} = $fil;
                #    ${$rsnf}{$ms} = $fil;
                #}
                #if ( ! is_in_array($ms,@subsnotfound) ) {
                #    prtw("[10] WARNING:1: No substitution for [$ms] found in hash ...\n" ) if ($dbg_s10);
                #    push(@subsnotfound,$ms);
                #}
            }
        }

        if ($val ne $orgval) {
            ${$rhash}{$key} = $val;
        }
        $len = length($key);
        $min = $len if ($len > $min);
    }

    # try to do substitutions, TWICE
    foreach $key (@am_rh_skeys) {
        $val = ${$rhash}{$key};
        next if (!defined $val || (length($val) == 0));
        $orgval = $val;
        if ($val =~ /\$\((\w+)\)/) {
            $ms = $1;
            $val2 = '';
            $fnd = 0;
            if (defined ${$rhash}{$ms}) {
                $val2 = ${$rhash}{$ms};
                $fnd = 3;
            } elsif (defined ${$rcomsubs}{$ms}) {
                $val2 = ${$rcomsubs}{$ms}; # found in common
                $fnd = 2;
            } elsif (defined ${$rglobhash}{$ms}) {
                $val2 = ${$rglobhash}{$ms};
                $fnd = 1;
            } else {
                # hmmm, maybe like 'GFX_CODE if @USE_GLUT_FALSE@ = fg_os_osgviewer.cxx $(GFX_COMMON)'
                $val2 = '';
                foreach $ky2 (keys %{$rhash}) {
                    if ($ky2 =~ /^$ms/) {
                        $tmp = trim_all(${$rhash}{$ky2});
                        if (length($tmp)) {
                            $val2 .= ' ' if (length($val2));
                            $val2 .= $tmp;
                        }
                        $fnd = 4;
                    }
                }
            }
            if ($fnd > 0) {
                $val =~ s/\$\($ms\)/$val2/g;
                prt("[02]:2: Substitution DONE [$ms] to [$val2]. [$fnd] IGNORING CONDITIONS!\n") if ($dbg_s02);
            } else {
                if ( ! (defined ${$rdnf}{$ms} || defined ${$rsnf}{$ms}) ) {
                    prtw("[10] WARNING:1: No definition for [$ms] found in hash ...\n" ) if ($dbg_s10);
                    ${$rdnf}{$ms} = $am_fil;
                    ${$rsnf}{$ms} = $am_fil;
                }
            }
        }
        if ($val ne $orgval) {
            ${$rhash}{$key} = $val;
        }
    }

    my %htmp = ();
    ### my $max_of_type = ${$rparams}{'MAX_OF_TYPE'};
    my $add_rel_sources = ${$rparams}{'ADD_REL_SOURCE'};
    my $root_folder = ${$rparams}{'ROOT_FOLDER'};
    my $try_harder = ${$rparams}{'TRY_HARDER'};
    my $try_much_harder = ${$rparams}{'TRY_MUCH_HARDER'};
    my $ignore_EXTRA_DIST = ${$rparams}{'IGNORE_EXTRA_DIST'};
    foreach $key (@am_rh_skeys) {
        $val = ${$rhash}{$key};
        if (!defined $val) {
            delete ${$rhash}{$key};
            prtw("WARNING: Deleted key [$key] from hash ref! How did this get here?\n");
            next;
        }
        if ($key =~ /_PROGRAMS/) {
            push(@progkeys,$key);
            push(@progs,$val);
            $ms = "PROGRAMS";
        } elsif (($key =~ /_LIBRARIES/)||($key =~ /_LTLIBRARIES/)) {
            # note: _LIBRARIES   = static libraries
            # and : _LTLIBRARIES = shared libraries
            push(@libkeys,$key);
            push(@libs,$val);
            $ms = "LIBRARIES";
        } elsif (($key =~ /_SOURCES/)||($key =~ /_EXTRASOURCES/)||($key =~ /_AUXSOURCES/)) {
            # note: $(proj)_a_SOURCES  - for static libraries .a
            # and : $(proj)_la_SOURCES - for shared libraries .so 
            push(@srckeys,$key);
            ###push(@srcs,$val);    # will scan and massage the sources later
            $ms = "SOURCES";
        } elsif ($key =~ /LDADD/) {
            $ms = "LDADD";
        } else {
            $ms = "*SKIPPED*";  # we are SKIPPING these - check more
            if (($key =~ /_/) &&
                (($key =~ /PROGRAMS/)||($key =~ /LIBRARIES/)||($key =~ /SOURCES/))) {
                if (! defined ${$rexcept}{$key}) {
                    # found bin_JAVAPROGRAMS CSHARPPROGRAMS hello_RESOURCES
                    prtw("WARNING: *** CHECK ME *** Got [$key] val = [$val] *** CHECK ME ***\n".
                        " SHOULD THIS ITEMS BE INCLUDED IN THE ACCUMULATION [$am_fil]\n");
                    ${$rexcept}{$key} = 1; # only output ONCE
                    if ( !(($key =~ /JAVA/)||($key =~ /CSHARP/)||($key =~ /RESOURCES/)||($key =~ /PASCAL/)) ) {
                        prt("WARNING: exit_value being set!\n");
                        ${$rexit_val} = 1;
                    }
                }
            }
        }
        $htmp{$ms} = [] if ( ! defined $htmp{$ms});
        # list the sources, but this is JUST for DISPLAY
        #@av = split(/\s/,$val);    # SPLIT LIST
        @av = split(/[\s\|]/,$val); # SPLIT LIST
        $val = '';
        foreach $oky (@av) {
            $oky = path_u2d($oky);
            $oky =~ s/\\\\/\\/ while ($oky =~ /\\\\/); # eliminate duplicate back slashes
            if (($oky =~ /^\w{1}:/)||($oky =~ /^-/)) {
                $src = sub_root_dir($oky); # already has a DRIVE beginning, so use AS IS
            } else {
                $src = sub_root_dir($am_dir.$oky);
                $src = path_u2d($src);
                $src =~ s/\\\\/\\/ while ($src =~ /\\\\/); # eliminate duplicate back slashes
            }
            $val .= ' ' if (length($val));
            $val .= $src;
        }
        push(@{$htmp{$ms}}, [$key,$val]);
    }

    if ($dbg_s16) {
        $min = 0;
        prt("\n[16] Enumeration of the temporary HASH - only for DEBUG\n");
        foreach $ms (keys %htmp) {
            $ky = $htmp{$ms};
            $scnt = scalar @{$ky};
            prt("[16] $scnt of type [$ms] file [$am_fil]\n");
            for ($i = 0; $i < $scnt; $i++) {
                $src = ${$ky}[$i][0];
                $len = length($src);
                $min = $len if ($len > $min);
            }
            $min = $max_of_type if ($min > $max_of_type);
            for ($i = 0; $i < $scnt; $i++) {
                $src = ${$ky}[$i][0];
                $val = ${$ky}[$i][1];
                $src .= ' ' while (length($src) < $min);
                prt(" $src = [$val]\n");
            }
        }
        prt("[16] End enumeration of temporary hash...\n");
    }

    # =======================================================================
    if ($dbg_s02) {
        $val = scalar @am_rh_skeys;
        prt("\n[02] List of $val items in the HASH from [$am_fil]...\n");
        foreach $key (@am_rh_skeys) {
            $val = $$rhash{$key};
            next if (($key eq 'EXTRA_DIST')&&($ignore_EXTRA_DIST));
            $key .= ' ' while (length($key) < $min);
            prt(" $key = $val\n" );
        }
        prt("[02] Done List of $val items in the HASH from [$am_fil]...\n");
    }

    # ### PROCESS LIBRARY SOURCES - stored in $rlibs
    # ===========================
    my $rlh = ${$rparams}{'REF_LIBS_HASH'};
    my $dnskys = 0; # only display this 'SOURCE' set ONCE
    my ($ra,$max_srcs,$rtoh,$hkey,$got_lib);
    # if (($key =~ /_LIBRARIES/)||($key =~ /_LTLIBRARIES/)) {
    $max_srcs = 0;  # start looking for maximum
    $got_lib = 0;
    if (@libkeys) {
        $val = scalar @libkeys;
        prt( "[03] Find sources for [$val] LIBRARY keys ...\n" ) if ($dbg_s03);
        $tot_scnt = 0;
        foreach $key (@libkeys) {
            $val = ${$rhash}{$key};
            #@av = split(/\s/,$val);
            @av = split(/[\s\|]/,$val); # SPLIT LIST
            prt( "[03] Find sources for LIBRARY [$key] [$val]\n" ) if ($dbg_s03);
            foreach $oky (@av) {
                next if (length($oky) == 0);
                $ky = $oky;
                $ky =~ s/-/_/g;
                $ky =~ s/\./_/g;
                $ky =~ s/\|//g;
                $ky = trim_all($ky);
                next if (length($ky) == 0);
                if (($ky =~ /\@/)||($ky =~ /\$/)) {
                    prtw("WARNING:1: Skipping a MACRO [$ky], in library [$key]! [$val] CHECK ME!\n");
                    next;
                }
                prt( "[03] Finding ORIGINAL [$oky] MODIFIED [$ky] Underscore and dot replaced\n" ) if ($dbg_s03);
                next if (length($ky) == 0);
                #next if (($ky =~ /\@/)||($ky =~ /\$/));
                $vky = $ky.'_SOURCES';
                $fnd = 0;
                #if (defined ${$rhash}{$vky}) {
                #    $val = ${$rhash}{$vky};
                #    $fnd = 1;
                #    prt("[03] Source list found with [$vky] = [$val]\n")  if ($dbg_s03);
                #} else {
                    my $src_list = '';
                    my @rhkeys = ();
                    #prt("[03] NO source list found with [$vky]... searching harder...\n")  if ($dbg_s03);
                    prt("[03] Finding source list with [$vky]... searching...\n")  if ($dbg_s03);
                    foreach $val (keys %{$rhash}) {
                        #if (($val =~ /$oky/) && ($val =~ /SOURCE/i)) {
                        if ( ($val eq $vky)||( (($val =~ /$oky/)||($val =~ /$ky/)) && ($val =~ /SOURCES/) )) {
                            push(@rhkeys,$val);
                            $vky = $val;
                            $src_list .= ' ' if (length($src_list));
                            $src_list .= ${$rhash}{$vky};
                            $fnd++;
                        }
                    }
                    if ($fnd) {
                        prt("[03] Source list found with $fnd keys [".join(" ",@rhkeys)."]\n") if ($dbg_s03);
                        $val = $src_list;
                        prt("[03] Source list [$val] dupes will be removed...\n")  if ($dbg_s03);
                    }
                #}
                if ($fnd) {
                    #@srcs = split(/\s/, $val);
                    @srcs = split(/[\s\|]/,$val); # SPLIT LIST
                    $scnt = scalar @srcs;
                    @psrcs = ();
                    %dupes = ();    # FIX20101028 - CLEAR dupes for EACH LIBRARY
                    # ====================================================================
                    prt("[03] Filter LIBRARY sources - $scnt...\n") if ($dbg_s03);
                    #  ensure DOS form, add $ff if add rel..
                    for ($i = 0; $i < $scnt; $i++) {
                        $val = $srcs[$i];   # extract a SOURCE
                        next if ((length($val) == 0)||($val =~ /^\s+$/)); # FIX20101028 - filter BLANKS
                        $src = path_u2d($val);  # to DOS form
                        next if (defined $dupes{$src});
                        $dupes{$src} = 1;   # done this source
                        if ($add_rel_sources) {
                            $ff = sub_root_dir($am_dir.$src);
                            if ($src ne $ff) {
                                prt("[18] LIB: Changed src from [$src], to [$ff]. [$am_dir]\n") if ($dbg_s18);
                                push(@psrcs,$ff);
                                $srcs[$i] = $ff;
                            } elsif ($src ne $val) {
                                prt("[18] LIB: Changed src from [$val] to [$src]\n") if ($dbg_s18);
                                push(@psrcs,$src);
                                $srcs[$i] = $src;
                            } else {
                                push(@psrcs,$val);
                            }
                        } else {
                            if ($src ne $val) {
                                prt("[18] LIB: Changed src from [$val] to [$src]\n") if ($dbg_s18);
                                $srcs[$i] = $src;
                            }
                            push(@psrcs,$src);
                        }
                    }
                    # final source array
                    $val = join(' ',@psrcs);
                    $scnt = scalar @psrcs;  # get SOURCE count for this LIBRARY [$ky]
                    $tot_scnt += $scnt;
                    if ($scnt > $max_srcs) {
                        $max_srcs = $scnt;  # store max count
                        $rtoh = $r_libs;    # keep the reference
                        $hkey = $ky;    # keep the 'key'
                        $got_lib = 1;
                    }
                    if (defined ${$r_libs}{$ky}) {
                        $ra = ${$r_libs}{$ky};
                        $ms = ${$ra}[0];
                        if ( value_not_in_first($ms,\$val) ) {
                            prtw( "WARNING: libraries [$ky] has value [$ms] ADDING [$val]!\n" );
                            #${$rlibs}{$ky} .= ' '.$val;
                            ${$ra}[0] .= ' '.$val;
                        }
                    } else {
                        ${$r_libs}{$ky} = [$val,$key];
                    }
                    prt( "[04] LIBRARY [$ky] [$key] has SOURCES $scnt [$val]\n" ) if ($dbg_s04);
                    # ====================================================================
                    # my $rlh = ${$rparams}{'REF_LIBS_HASH'};
                    ${$rlh}{$ky} = $rhash; # keep the original Makefile.am hash scan
                } else {
                    if (!$dnskys) {
                        $dnskys = 1;
                        $ms = '';
                        $scnt = 0;
                        foreach $val (keys %{$rhash}) {
                            if ($val =~ /SOURCE/i) {
                                $ms .= ' ' if (length($ms));
                                $ms .= $val;
                                $scnt++;
                            }
                        }
                        prt("But found $scnt keys [$ms] in HASH! Is it ONE of these?\n") if (length($ms));
                    }
                    prtw( "WARNING: No sources for LIBRARY [$ky] key [$vky] o [$oky],\n in file [$am_fil]\n" );
                }
            }
        }
        $val = scalar @libkeys;
        prt( "[03] Done sources for $val LIBRARY keys ... found $tot_scnt...\n" ) if ($dbg_s03);
    } else {
        prt( "[03] No LIBRARY keys ...\n" ) if ($dbg_s03);
    }

    #### PROCESS PROGRAM SOURCES - stored in $rprogs
    #### =======================
    my $rph = ${$rparams}{'REF_PROG_HASH'};
    if (@progkeys) {
        foreach $key (@progkeys) {
            $val = $$rhash{$key};
            #@av = split(/\s/,$val);
            @av = split(/[\s\|]/,$val); # SPLIT LIST
            foreach $oky (@av) {
                next if (length($oky) == 0);
                $ky = $oky;
                $ky =~ s/-/_/g;
                $ky =~ s/\./_/g;
                $ky = trim_all($ky);
                next if (length($ky) == 0);
                if (($ky =~ /\@/)||($ky =~ /\$/)) {
                    prtw("WARNING:2: Skipping a MACRO [$ky], in program [$key]! [$val] CHECK ME!\n");
                    next;
                }
                $vky = $ky.'_SOURCES';
                $fnd = 0;
                $ky2 = $oky;
                if (defined $$rhash{$vky}) {
                    $val = $$rhash{$vky};
                    $ky2 = $vky;
                    $fnd = 1;
                } else {
                    $fnd = 0;
                    foreach $ky2 (keys %{$rhash}) {
                        if (($ky2 =~ /$oky/) && ($ky2 =~ /_SOURCE/)) {
                            $fnd++;
                        }
                    }
                    prtw("WARNING: Found $fnd candidates seeking [$oky]\n") if ($fnd > 1);
                    $fnd = 0;
                    foreach $ky2 (keys %{$rhash}) {
                        if (($ky2 =~ /$oky/) && ($ky2 =~ /_SOURCE/)) {
                            $val = ${$rhash}{$ky2};
                            $fnd = 2;
                            last;
                        }
                    }
                }
                if (!$fnd && $try_harder) {
                    # search the HASH harder
                    foreach $ky2 (keys %{$rhash}) {
                        $val2 = $$rhash{$ky2};
                        @srcs = split(/[\s\|]/,$val2); # SPLIT LIST
                        foreach $src (@srcs) {
                            if (($src =~ /$oky\./) && is_c_source_extended($src) ) {
                                $val = $src;
                                $fnd = 3;
                                last;
                            }
                        }
                    }
                }
                if (!$fnd && $try_much_harder && ($oky =~ /^[-\w\.]+$/)) {
                    # do_dir_scan($root_folder,0) if (!$done_dir_scan);
                    @srcs = ();
                    $fcnt = ac_match_dir_for_c_source($rparams,$oky,$am_dir,\@srcs);
                    if ($fcnt) {
                       $scnt = scalar @srcs;
                       $val = $srcs[0];
                       prtw("WARNING: Found $scnt in match for c source (like ".$srcs[1].")! Using [$val]\n") if ($scnt > 1);
                       $ky2 = $oky;
                       $fnd = 4;
                    }
                }
                if ($fnd && length($val)) {
                    #@srcs = split(/\s/, $val);
                    @srcs = split(/[\s+\|]/,$val); # SPLIT LIST
                    $scnt = scalar @srcs;
                    @psrcs = ();
                    %dupes = ();    # FIX20101028 - Added dupes for EACH PROGRAM
                    # ====================================================================
                    prt("[03] Filter PROGRAM sources - $scnt from [$val] - f=$fnd k=[$ky2] \n") if ($dbg_s03);
                    for ($i = 0; $i < $scnt; $i++) {
                        $val = $srcs[$i];
                        if ((length($val) == 0)||($val =~ /^\s+$/)) { # FIX20101028 - filter BLANKS
                            prt("[18] PRG: Blank source filtered [$val]\n") if ($dbg_s18);
                            next;
                        }
                        $src = path_u2d($val);
                        if (defined $dupes{$src}) { # FIX20101028 - Avoid dupes for EACH PROGRAM
                            prt("[18] PRG: Duplicate source filtered [$src] [$val]\n") if ($dbg_s18);
                            next;
                        }
                        $dupes{$src} = 1;
                        if ($add_rel_sources) {
                            $ff = sub_root_dir($am_dir.$src);
                            if ($src ne $ff) {
                                prt("[18] PRG:ARS: Changed src from [$src], to [$ff].") if ($dbg_s18);
                                $srcs[$i] = $ff;
                                push(@psrcs,$ff);
                                $ff = $am_dir.$ff;
                            } elsif ($src ne $val) {
                                prt("[18] PRG:ARS: Changed src from [$val], to [$src].") if ($dbg_s18);
                                $srcs[$i] = $src;
                                push(@psrcs,$src);
                                $ff = $am_dir.$src;
                            } else {
                                # FIX20120522 - If just ONE, then $src eq $val
                                prt("[18] PRG:ARS: No change [$val], storing src [$src].") if ($dbg_s18);
                                push(@psrcs,$src);
                                $ff = $am_dir.$src;
                            }
                            $ok = (-f $ff) ? "ok" : "NF";
                            prt(" $ok\n") if ($dbg_s18);
                        } elsif ($src ne $val) {
                            prt("[18] PRG: Changed src from [$val], to [$src].\n") if ($dbg_s18);
                            $srcs[$i] = $src;
                            push(@psrcs,$src);
                        } else {
                            # FIX20120522 - If just ONE, then $src eq $val
                            prt("[18] PRG: No change [$val], storing [$src].\n") if ($dbg_s18);
                            push(@psrcs,$src);
                        }
                    }

                    $val = join(' ',@psrcs);
                    $scnt = scalar @psrcs;
                    if (!$got_lib && ($scnt > $max_srcs)) {
                        $max_srcs = $scnt;  # store max count
                        $rtoh = $r_progs;    # keep the reference
                        $hkey = $ky;    # keep the 'key'
                    }
                    if (defined ${$r_progs}{$ky}) {
                        $ra = ${$r_progs}{$ky};
                        $ms = ${$ra}[0];
                        if ( value_not_in_first($ms,\$val) ) {
                            prtw( "WARNING: programs [$ky] has value [$ms] ADDING [$val]!\n" );
                            #${$rprogs}{$ky} .= ' '.$val;
                            ${$ra}[0] .= ' '.$val;
                        }
                    } else {
                        ${$r_progs}{$ky} = [$val,$key];
                    }
                    # my $rph = ${$rparams}{'REF_PROG_HASH'};
                    ${$rph}{$ky} = $rhash; # keep the original Makefile.am hash scan
                    prt( "[04] PROGRAM [$ky] [$key] has $scnt SOURCES [$val]\n" ) if ($dbg_s04);
                    # ====================================================================
                } else {
                    $fnd = 0;
                    if ($try_harder) {
                        $val = '';
                        if ( a_source_does_exist($am_dir,$oky,\$val) ) {
                            $fnd = 1;
                            if (defined ${$r_progs}{$ky}) {
                                $ra = ${$r_progs}{$ky};
                                $ms = ${$ra}[0];
                                if ( value_not_in_first($ms,\$val) ) {
                                    prtw( "WARNING: programs [$ky] has value [$ms] ADDING [$val]!\n" );
                                    #${$rprogs}{$ky} .= ' '.$val;
                                    ${$ra}[0] .= ' '.$val;
                                }
                            } else {
                                ${$r_progs}{$ky} = [$val,$key];
                            }
                            # my $rph = ${$rparams}{'REF_PROG_HASH'};
                            ${$rph}{$ky} = $rhash; # keep the original Makefile.am hash scan
                            prt("[04] PROGRAM [$ky] [$key] has existing SOURCE [$val]\n") if ($dbg_s04);
                        }
                    }
                    if (!$fnd) {
                        if (!$dnskys) {
                            $dnskys = 1;
                            $ms = '';
                            $scnt = 0;
                            foreach $val (keys %{$rhash}) {
                                if ($val =~ /SOURCE/i) {
                                    $ms .= ' ' if (length($ms));
                                    $ms .= $val;
                                    $scnt++;
                                }
                            }
                            prt("\nBut found $scnt keys\n [$ms] in HASH!\n Is it ONE of these?\n") if (length($ms));
                        }
                        prtw("WARNING: No sources for PROGRAM [$ky] key [$vky] org [$oky] file [$am_fil]\n" );
                    }
                }
            }
        }
    } else {
        prt( "[03] No PROGRAM keys ...\n" ) if ($dbg_s03);
    }

    # Check for 'include_HEADERS'
    # ===========================================================
    # TODO ***TBD*** - In fact if this EXISTS, then for cmake 
    # this should give the installed headers for this project,
    # thus other headers should go to another variable, say 'other_HDRS' and NOT be 'installed'
    $key = 'include_HEADERS';
    $val = '';
    if (defined ${$rhash}{$key}) {
        $val = ${$rhash}{$key};
    } else {
        # but the 'key' may be a CONDITIONAL, like 'include_HEADERS if BUILD_JS@_TRUE@'
        foreach $key (keys %{$rhash}) {
            if ($key =~ /include_HEADERS\s+/) {
                $val = ${$rhash}{$key};
                last;
            }
        }
    }
    if (length($val)) {
        @srcs = split(/[\s+\|]/,$val); # SPLIT LIST
        $scnt = scalar @srcs;
        if ($max_srcs) {
            $ra = ${$rtoh}{$hkey};
            $val2 = ${$ra}[0];  # get current source
            prt("[04] Project [$hkey]: Adding [$val] to sources [$val2]! NEW 20120528\n") if ($dbg_s04);
            ${$ra}[0] .= ' '.$val;
        } else {
            prtw("WARNING: No 'max_srcs' for LIBRARIES nor PROGRAM, so unable to add [$val] list!\n");
        }
    }
    # ===========================================================
    my $ramsdone = ${$rparams}{'REF_AMS_DONE'};
    my $am_cnt   = scalar keys(%{$ramsdone});
    my $prog_cnt = scalar keys(%{$r_progs});
    my $libs_cnt = scalar keys(%{$r_libs});
    if ($am_cnt && (!$prog_cnt && !$libs_cnt)) {
        # did, one or more AM (or IN) files, but NO libraries, or programs
        # my $ref_targets = ${$rparams}{'AM_FILE_TARGETS'};
        my $rtcnt = scalar keys(%{$ref_targets});
        if ($rtcnt && (defined ${$rparams}{'SUPP_MAKE_IN'} ) && (${$rparams}{'SUPP_MAKE_IN'} > 0)) {
            process_target_list($rparams);
        } elsif ($rtcnt) {
            prt("[03] NOTE: Would scan the $rtcnt TARGETS, if \$supp_make_in was set!\n") if ($dbg_s03);
        }
    }

    prt( "[02] extract_from_hash: Done $acnt from [$am_fil] or [".sub_root_folder($am_fil)."]...\n" ) if ($dbg_s02);

    # return \%extract;
}

# 1: $(MACRO)
# 2: ${MACRO}
# 3: @MACRO@
sub is_macro_type($) {
    my ($txt) = @_;
    return 1 if ($txt =~ /^\$\(\w+\)$/);  # 1: $(MACRO)
    return 2 if ($txt =~ /^\$\{\w+\}$/);  # 2: ${MACRO}
    return 3 if ($txt =~ /^\@\w+\@$/);  # 3: @MACRO@
    return 0;
}

sub add_2_hoh_subs($$$$) {
    my ($fil,$rparams,$key,$val) = @_;
    my $rhohsubs = ${$rparams}{'REF_HOH_SUBS'};
    if (defined ${$rhohsubs}{$fil}) {
        if (defined ${$rhohsubs}{$fil}{$key}) {
            ${$rhohsubs}{$fil}{$key} .= ' '.$val; # if (length($val));
            prt("[23] HOH_SUBS: Added VALUE [$fil] [$key] [$val]\n") if ($dbg_s23);
        } else {
            ${$rhohsubs}{$fil}{$key} = $val;
            prt("[23] HOH_SUBS: Set VALUE [$fil] [$key] [$val]\n") if ($dbg_s23);
        }
    } else {
        ${$rhohsubs}{$fil}{$key} = $val;
        prt("[23] HOH_SUBS: Set NEW [$fil] [$key] [$val]\n") if ($dbg_s23);
    }
}

# lev = 1 = no plus sign, so should be first init of item
#           and warn if it is NOT
# lev = 2 = Had a plus sign, is += so variable SHOULD exist
#           and warn if it does NOT, if $warn_on_plus
#sub add_key_value_2_hash($$$$$$) {
#    my ($key,$val,$rhash,$i2,$sfil,$lev) = @_;
sub add_key_value_2_hash($$$) {
    my ($rparams,$first,$lev) = @_;
    my $rhash = ${$rparams}{'CURR_REF_HASH'};
    my $i2 = ${$rparams}{'CURR_LINENUM'};
    my $ckey = ${$rparams}{'CURR_KEY'};
    my $val = ${$rparams}{'CURR_VAL'};
    my $sfil = ${$rparams}{'AM_FILE'};
    my $warn_on_plus = ${$rparams}{'VALUE_WARN_ON_PLUS'};
    my $key = $ckey;
    my ($tmp,$done,$cval,$msg);
    if ( is_macro_type($val) ) {
        if ($avoid_adding_macro) {
            prt("[12] $i2: key [$key] Avoided adding MACRO value [$val] type $first, lev $lev\n") if ($dbg_s12);
            return 0;
        }
        prt("[12] $i2: key [$key] NOTE: Adding MACRO value [$val] type $first, lev $lev\n") if ($dbg_s12);
    }
    if ($val =~ /^\w{1}:/) {
        # if the value is a DOS 'D:' path
        $tmp = path_u2d($val);
        $tmp =~ s/\\\\/\\/ while ($tmp =~ /\\\\/); # remove any double '\\' in string
        if ($val ne $tmp) {
            prt("[12] Modifd [$val]\n[12] to     [$tmp]\n") if ($dbg_s12);
            $val = $tmp;
        }
        $tmp = '';
    }
    add_2_hoh_subs($sfil,$rparams,$key,$val) if (($key =~ /^SUBDIRS/) && (length($val)) && (!($val =~ /^\s+$/)));
    # add_2_hoh_subs($sfil,$rparams,$key,$val) if ($key =~ /^SUBDIRS/);
    $cval = '';
    if (defined ${$rhash}{$key}) {
        $cval = ${$rhash}{$key};
        $val = get_only_new_items($cval,$val) if (length($cval));   # try to reduce addition, if poss...
        if (length($val)) {
            prtw( "WARNING:1: $i2: hash [$key] exists with [$cval]! Adding [$val]! typ=$first, lev=$lev! file [$sfil]\n" )
                if (($first == 1) && length($cval));
            # ${$rhash}{$key} .= '|'.$val;
            if ( length($cval) && !($cval =~ /^\s+$/) ) {
                ${$rhash}{$key} .= ' '.$val;
                $tmp = 'Added to';
            } else {
                ${$rhash}{$key} = $val;
                $tmp = 'Setting2'
            }
        } else {
            $tmp = 'None2Add'
        }
    } else {
        # hmmm, maybe have a key like 'jack_freebob_la_SOURCES if HAVE_ALSA_MIDI@_TRUE@'
        # double hmmm, if it is like the above, then SHOULD I store it under 'jack_freebob_la_SOURCES'
        # or if necessary create a NEW key ?????
        $done = 0;
        if ($key =~ /\s/) {
            my @arr = split(/\s/,$key);
            my $cnt = scalar @arr;
            $tmp = $arr[0];
            if ($cnt >= 3) {
                if ( defined ${$rhash}{$tmp} ) {
                    $key = $tmp;
                    $cval = ${$rhash}{$key};
                    $val = get_only_new_items($cval,$val) if (length($cval));   # try to reduce addition, if poss...
                    if (length($val)) {
                        if ( length($cval) && !($cval =~ /^\s+$/) ) {
                            ${$rhash}{$key} .= ' '.$val;
                            $tmp = 'Added (assume TRUE)';
                            prtw( "WARNING:2: $i2: hash [$key] exists with [$cval]!\n Adding [$val]! typ=$first, lev=$lev! file [$sfil]\n" )
                                if ($first == 1);
                        } else {
                            ${$rhash}{$key} = $val;
                            $tmp = 'Set to (assume TRUE)';
                        }
                    } else {
                        $tmp = 'No New to Add';
                    }
                    $done = 1;
                }
            } else {
                prtw("WARNING: Key [$key] DID NOT SPLIT into 3 or more parts! WHAT IS THIS??\n");
            }
        }
        if (!$done) {
            prtw( "WARNING: $i2: hash [$key] DOES NOT EXIST! typ=$first, lev=$lev! file [$sfil]\n" ) if (($first == 2) && $warn_on_plus);
            ${$rhash}{$key} = $val;
            $tmp = 'Setting'
        }
    }
    if ($dbg_s12) {
        # examples of output
        # [12] 65: Setting key [lib_LTLIBRARIES], with value [libjpeg.la] typ=1, lev=0
        # [12] 68: Setting key [libjpeg_la_SOURCES], with value [jaricom.c ...] typ=1, lev=0
        # [12] 97: Setting key [include_HEADERS], with value [jerror.h jmorecfg.h jpeglib.h] typ=1, lev=0
        # [12] 100: Setting key [noinst_HEADERS], with value [cderror.h cdjpeg.h ...] typ=1, lev=0
        $msg = "[12] $i2: $tmp key [$key], with value [$val] ";
        $msg .= "had [$cval] " if (length($cval));
        $msg .= "org [$ckey] " if ($key ne $ckey);
        $msg .= "typ=$first, lev=$lev";
        prt("$msg\n");
    }
    return 1;
}

sub not_same_dirs($$) {
    my ($d1,$d2) = @_;  # like ($ifcond,$curr_srcdir)
    my $dd1 = uc(path_u2d($d1));
    my $dd2 = uc(path_u2d($d2));
    $dd1 .= "\\" if ( !($dd1 =~ /\\$/) );
    $dd2 .= "\\" if ( !($dd2 =~ /\\$/) );
    return 0 if ($dd1 eq $dd2);
    return 1;
}

# Process a Makefile.am file
sub am_process_AM_file($$) {
    my ($rparams,$lev) = @_;
    my ($fil,$pfil);
    if ($lev > 0) {
        $fil = ${$rparams}{'AM_FILE_INC'};
        $pfil = ${$rparams}{'AM_FILE'};
    } else {
        # level 0
        $fil = ${$rparams}{'AM_FILE'};
        $pfil = '';
    }
    ### my $ref_progs = ${$rparams}{'REF_PROGRAMS'};
    ### my $ref_libs = ${$rparams}{'REF_LIBRARIES'};
    my $rexit_val = ${$rparams}{'REF_EXIT_VALUE'};
    # 27/09/2010 - user conditionals, and missed conditionals
    my $rusrcond = ${$rparams}{'REF_DEF_CONDITIONS'};
    my $rmiscond = ${$rparams}{'REF_MISSED_CONDITIONS'};

    my ($a_nm, $a_dir) = fileparse($fil);
    $a_dir = $cwd."\\" if ($a_dir =~ /^\.(\\|\/)$/);
    my $rcs = ${$rparams}{'CURR_COMMON_SUBS'};
    if (($lev == 0) && $set_srcdir_local) {
        # set 'srcdir' to directory of THIS am file...
        ${$rcs}{'srcdir'} = $a_dir;
    }
    my $curr_srcdir = ${$rcs}{'srcdir'};
    my $sfil = sub_root_folder($fil);
    my ($rhash,$reftarg);
    $rhash = ${$rparams}{'CURR_REF_HASH'};
    $reftarg = ${$rparams}{'AM_FILE_TARGETS'};
    my ($ff);
    my $dooldext = 0;
    if (!open INF, "<$fil") {
        prtw( "WARNING: Unable to open $fil ... $! ...\n" );
        return $rhash;
    }
    my @lns = <INF>;
    close INF;
    my $cnt = scalar @lns;
    ${$rparams}{'TOTAL_LINE_COUNT'} += $cnt;
    ${$rhash}{'CURR_AM_FILE'} = $fil;     # store full path Makefile.am to $rhash
    prt("\n") if ($dbg_s07 && $dbg_s08);
    prt( "[08] AM: Processing $cnt lines, from [$fil] ...\n" ) if ($dbg_s08);
    my ($i,$line,$fline,$i2,@av,$key,$val,$j,$acnt,$ifcond,$msg);
    my ($ind,$len,$tmp,$scnt);
    my ($irh,$k,$v,$sff);
    my @cond_stack = ();
    my $in_target = 0;
    my $target = '';
    $fline = '';
    for ($i = 0; $i < $cnt; $i++) {
        $line = $lns[$i];
        $i2 = $i + 1;
        chomp $line;
        $line = trim_all($line);
        prt("[01] $i2: [$line]\n") if ($dbg_s01);
        next if ($line =~ /^#/);
        $fline .= $line;
        #$len = length($fline);
        #if ($len == 0) {
        #    $in_target = 0;
        #    next;
        #}
        # join continuation lines into one
        if ($fline =~ /\\$/) {
            $fline =~ s/\\$/ /;
            next;
        }
        # deal with the FULL line
        $fline = trim_all($fline);
        if ($fline ne $line) {
            prt("[01] $i2: [$fline] accumulated...\n") if ($dbg_s01);
        }
        $len = length($fline);
        if ($len == 0) {
            $in_target = 0;
            next;
        }
        ${$rparams}{'CURR_LINE'} = $fline;
        ${$rparams}{'CURR_LINENUM'} = $i2;
        #$fline = test_for_substitution($fline,$refhash,$i2,$sfil);
        $fline = am_test_for_substitution($rparams);

        if ($fline =~ /$IFEQ_PATTERN/o) {
            # open an IF
            $ifcond = $1;
            @av = split(',',$ifcond);
            $ifcond = trim_all($av[0]);
            $acnt = scalar @av;
            $v = 'TRUE';
            if ($acnt > 1) {
                $v = 'FALSE' if ($ifcond ne $av[1]);
            } else {
                $v = 'FALSE' if (not_same_dirs($ifcond,$curr_srcdir));
            }
            $key = $ifcond."\@_".$v."\@";
            push(@cond_stack,$key);
            $scnt = scalar @cond_stack;
            $msg = '';
            prt( "[06] IFEQ:$scnt: Opened cond_stack with [".$cond_stack[$#cond_stack]."] $msg [$sfil]\n" ) if ($dbg_s06);
        } elsif ($fline =~ /$IFNEQ_PATTERN/o) {
            # open an IF
            $ifcond = $1;
            @av = split(',',$ifcond);
            $ifcond = trim_all($av[0]);
            $acnt = scalar @av;
            $v = 'FALSE';
            if ($acnt > 1) {
                $v = 'TRUE' if ($ifcond ne $av[1]);
            } else {
                $v = 'TRUE' if (not_same_dirs($ifcond,$curr_srcdir));
            }
            $key = $ifcond."\@_".$v."\@";
            push(@cond_stack,$key);
            $scnt = scalar @cond_stack;
            $msg = '';
            prt( "[06] IFNEQ:$scnt: Opened cond_stack with [".$cond_stack[$#cond_stack]."] $msg [$sfil]\n" ) if ($dbg_s06);
        } elsif (($fline =~ /$IF_PATTERN/o)||($fline =~ /$IFD_PATTERN/o)) {
            # open an IF
            $ifcond = $1;
            push(@cond_stack, $ifcond . "\@_TRUE\@");
            $scnt = scalar @cond_stack;
            $msg = '';
            $v = 'TRUE';
            if ( defined ${$rusrcond}{$ifcond} ) {
                $v = ${$rusrcond}{$ifcond};
                $msg = "UDEF $v";
            } else {
                # put in MISSED conditionals
                $msg = 'MISSED';
                if (defined ${$rmiscond}{$ifcond}) {
                    ${$rmiscond}{$ifcond} .= '|'.$v;
                    $msg .= '+';
                } else {
                    ${$rmiscond}{$ifcond} = $v;
                }
            }
            prt( "[06] IF:$scnt: Opened cond_stack with [".$cond_stack[$#cond_stack]."] $msg [$sfil]\n" ) if ($dbg_s06);
            #$in_target = 0;
        } elsif (($fline =~ /$NIF_PATTERN/o)||($fline =~ /$NIF_PATTERN2/o)) {
            # open an IF !(SOMETHING)
            $ifcond = $1;
            push(@cond_stack, $ifcond . "\@_FALSE\@");
            $msg = '';
            $v = 'FALSE';
            if ( defined ${$rusrcond}{$ifcond}) {
                $v = ${$rusrcond}{$ifcond};
                $msg = "UDEF $v";
            } else {
                # put in MISSED conditionals
                $msg = 'MISSED';
                if (defined ${$rmiscond}{$ifcond}) {
                    ${$rmiscond}{$ifcond} .= '|'.$v;
                    $msg .= '+';
                } else {
                    ${$rmiscond}{$ifcond} = $v;
                }
            }
            prt( "[06] NIF:$scnt: Opened cond_stack with [".$cond_stack[$#cond_stack]."] $msg [$sfil]\n" ) if ($dbg_s06);
            #$in_target = 0;
        } elsif ($fline =~ /$ELSE_PATTERN/o) {
            # switch to else
            $scnt = scalar @cond_stack;
            if ($scnt) {
                $ifcond = $cond_stack[$#cond_stack];
                $msg = 'UNKNOWN';
                if ($ifcond =~ /(\@_TRUE\@|\@_FALSE\@)/) {
                    $msg = $1;
                    $ifcond =~ s/(\@_TRUE\@|\@_FALSE\@)//;
                }
                if ($cond_stack[$#cond_stack] =~ /\@_TRUE\@$/) {
                    $v = 'FALSE';
                    $cond_stack[$#cond_stack] =~ s/\@_TRUE\@$/\@_FALSE\@/;
                    $msg .= " to $v";
                } else {
                    $v = 'TRUE';
                    $cond_stack[$#cond_stack] =~ s/\@_FALSE\@$/\@_TRUE\@/;
                    $msg .= " to $v";
                }
                if ( defined ${$rusrcond}{$ifcond}) {
                    $msg .= " UDEF ".${$rusrcond}{$ifcond};
                } else {
                    # put in MISSED conditionals
                    $msg .= ' MISSED';
                    if (defined ${$rmiscond}{$ifcond}) {
                        ${$rmiscond}{$ifcond} .= '|'.$v;
                        $msg .= '+';
                    } else {
                        ${$rmiscond}{$ifcond} = $v;
                    }
                }
                prt( "[06] Else:$scnt: Switched cond_stack to [".$cond_stack[$#cond_stack]."] $msg [$sfil]\n" ) if ($dbg_s06);
            } else {
                prtw( "POTENTIAL ERROR: else without if or nif! [$fil:$i2]\n" );
                prt("WARNING: exit_value being set!\n");
                ${$rexit_val} = 1;
            }
            #$in_target = 0;
        } elsif ($fline =~ /$ENDIF_PATTERN/o) {
            # reached endif
            if (! @cond_stack) {
                prtw( "ERROR: endif without if! ($sfil:$i2)\n" );
            } else {
                $ifcond = pop (@cond_stack);
                prt( "[06] Closed cond_stack with [$ifcond] $sfil\n" ) if ($dbg_s06);
            }
            #$in_target = 0;
        #} elsif ($fline =~ /$INCLUDE_PATTERN/o) {
        } elsif (($fline =~ /$INCLUDE_PATTERN/o)||($fline =~ /$INCLUDE_PATTERN2/)) {
            $key = $1;
            if ($key =~ /^\w{1}:(.+)$/) {
                $ff = $key;
            } else {
                $ff = $a_dir.$key;
            }
            $ff = path_d2u($ff);
            $ff = fix_rel_path3($ff,'process_AM_file');
            $ff =~ s/\\\\/\\/ if ($ff =~ /\\\\/);
            if ($cairo_special_fix) {
                # special FIX for cairo project, where this is done in m4 macros
                if ($ff =~ /Makefile\.am/) {
                    $val = $ff;
                    $val =~ s/Makefile\.am/Makefile\.win32/;
                    if (-f $val) {
                        prt( "[08] cairo_special_fix: CHANGED INCLUDE to file [$val], from [$ff] ...\n" ) if ($dbg_s08);
                        $ff = $val
                    }
                }
            }
            $sff = sub_root_folder($ff);
            if (-f $ff) {
                prt( "[08] Processing INCLUDE file [$ff], from [$fil] ...\n" ) if ($dbg_s08);
                ${$rparams}{'AM_FILE_INC'} = $ff;   # set INC file to SCAN
                $irh = am_process_AM_file($rparams,($lev+1));
                prt( "[08] DONE Processing INCLUDE file [$ff], from [$fil] ...\n\n" ) if ($dbg_s08);
            } else {
                prtw("WARNING: Unhandled INCLUDE [$key], [$ff] NOT FOUND! in [$sfil] at $i2\n" );
            }
        } elsif ($fline =~ /^(\w+)\s*=\s*(.*)$/) {
            #$key = $1;
            @av = split('=',$fline);
            $key = trim_all($av[0]);
            $acnt = scalar @av;
            $val = '';  # start with NO VALUE
            # if can be just 'JPEG_SERVER ='
            for ($j = 1; $j < $acnt; $j++) {
                if ($j == 1) {
                    $val = trim_all($av[$j]);
                } else {
                    $val .= '='.trim_all($av[$j]);
                }
            }
            # FIX20110803 - watch out for
            # E01 = e01_8.c # e01_2.c e01_3.c e01_4.c e01_5.c e01_6.c e01_7.c
            if ($val =~ /\#/) {
                $tmp = $val;
                $val =~ s/\#.*$//;
                if ($val =~ /\#/) {
                    pgm_exit(1,"INTERNAL ERROR: Removal of '#...' FAILED!\nline [$fline] val [$val] file: [$fil]\n");
                }
                $val = trim_all($val);
                prt( "[08] Removed '#' from [$tmp], to [$val], from [$fil]\n" ) if ($dbg_s08);
            }
            #show_line_split($fline,$key,$val,\@av,$i2);
            if (@cond_stack) {
                $ifcond = $cond_stack[$#cond_stack];
                $key .= ' if '.$ifcond;
            }
            if (length($key) == 0) {
                pgm_exit(1,"ERROR: Split of line [$fline] DID NOT YIELD key! Losing value [$val]\n");
            } else {
                ${$rparams}{'CURR_LINENUM'} = $i2;
                ${$rparams}{'CURR_KEY'} = $key;
                ${$rparams}{'CURR_VAL'} = $val; # this can be a BLANK
                #add_key_value_2_hash($key,$val,$refhash,$i2,$sfil,1); # should NOT exist
                add_key_value_2_hash($rparams,1,$lev); # should NOT exist
            }
        } elsif ($fline =~ /^(\w+)\s*\+=\s*(.+)$/) {
            $key = $1;
            $val = $2;
            if (@cond_stack) {
                $ifcond = $cond_stack[$#cond_stack];
                $key .= ' if '.$ifcond;
            }
            # FIX20110803 - watch out for
            # E01 = e01_8.c # e01_2.c e01_3.c e01_4.c e01_5.c e01_6.c e01_7.c
            if ($val =~ /\#/) {
                $val =~ s/\#.*$//;
                if ($val =~ /\#/) {
                    pgm_exit(1,"INTERNAL ERROR: Removal of '#...' FAILED!\nline [$fline] val [$val] file: [$fil]\n");
                }
                $val = trim_all($val);
                prt( "[08] +Removed '#' from [$tmp], to [$val], from [$fil]\n" ) if ($dbg_s08);
            }
            ${$rparams}{'CURR_LINENUM'} = $i2;
            ${$rparams}{'CURR_KEY'} = $key;
            ${$rparams}{'CURR_VAL'} = $val;
            #add_key_value_2_hash($key,$val,$refhash,$i2,$sfil,2); # plus, so key SHOULD exist
            add_key_value_2_hash($rparams,2,$lev); # plus, so key SHOULD exist
        } elsif ($fline =~ /^([\.\w-]+)\s*:/) {
            $target = $1;
            $in_target = 1;
            $val = '';
            $ind = index($fline,':');
            if (($ind > 0) && (($ind+1) < $len)) {
                $val = trim_all(substr($fline,($ind+1)));
            }
            if (@cond_stack) {
                $ifcond = $cond_stack[$#cond_stack];
                $target .= ' if '.$ifcond;
            }
            if (defined ${$reftarg}{$target}) {
                ##prtw( "WARNING: targets[$target] exists with [".$targets{$target}."]! Adding [$val]!! file=$sfil\n" );
                ${$reftarg}{$target} .= "\n\t".$val;
                $tmp = 'Added to';
            } else {
                ${$reftarg}{$target} = $val;
                ##prtw( "WARNING: targets[$target] DOES NOT exist! Adding [$val]!! file=$sfil\n" );
                $tmp = 'Started';
            }
            prt("[11] $i2: [$tmp] TARGET [$target], with value [$val]\n") if ($dbg_s11);
        } elsif ($fline =~ /^([-\@\w]+)\s*=\s*(.*)$/) {
            $key = $1;
            $val = trim_all($2);
            if (@cond_stack) {
                $ifcond = $cond_stack[$#cond_stack];
                $key .= ' if '.$ifcond;
            }
            if (length($key) == 0) {
                pgm_exit(1,"ERROR: Split of line [$fline] DID NOT YIELD key! Losing value [$val]\n");
            } else {
                ${$rparams}{'CURR_LINENUM'} = $i2;
                ${$rparams}{'CURR_KEY'} = $key;
                ${$rparams}{'CURR_VAL'} = $val;
                #add_key_value_2_hash($key,$val,$refhash,$i2,$sfil,1); # should NOT exist
                add_key_value_2_hash($rparams,1,$lev); # should NOT exist
            }
        } else {
            if ($in_target && length($target)) {
                if (defined ${$reftarg}{$target}) {
                    ${$reftarg}{$target} .= "\n\t".$fline;
                } else {
                    ${$reftarg}{$target} = $fline;
                    ##prtw( "WARNING: targets[$target] DOES NOT exist! Adding [$val]!! file=$sfil\n" );
                }
                prt("[11] $i2: Added to targets [$target] value [$fline]\n") if ($dbg_s11);
            } else {
                prt("[01] $i2: [$fline] SKIPPED file=[$fil]\n" ) if ($dbg_s01);
            }
        }
        $fline = '';    # kill this processed line
        $key = '';
        $val = '';
    }

    if ($lev == 0) {
        # done all the LINES, now play with the HASH collected
        $acnt = scalar keys(%{$rhash});
        if ($acnt) {
            #my $rextr = extract_from_hash( $fil, $refhash, $rprogs, $rlibs );
            my $rextr = am_extract_from_hash($rparams);
        } else {
            prt( "NOTE: NO KEYS IN HASH! for [$fil] $cnt lines...\n" );
        }
        ${$rhash}{':_AM_FILE_SRC_:'} = $fil;
        add_2_hoh_subs($fil,$rparams,'SUBDIRS',"."); # ensure a SUBDIRS entry, whether one or not
    }
    # WARN if conditional stack NOT closed
    if (@cond_stack) {
        $val = join("\n",@cond_stack);
        prtw( "WARNING: Items still in cond_stack! [$val]\n file [$fil]\n" );
    }
    return $rhash;
}

# show a SCALAR only reference hash
# that is where all the keys and values are scalar only
sub show_scalar_ref_hash($) {
    my ($rhash) = @_;
    my $cnt = scalar keys(%{$rhash});
    prt("Got $cnt keys for this HASH...\n");
    my ($min,$key,$max,$val,$len);
    $min = 0;
    $max = 40;
    foreach $key (keys %{$rhash}) {
        $len = length($key);
        $min = $len if ($len > $min);
    }
    $min = $max if ($min > $max);
    foreach $key (keys %{$rhash}) {
        $val = ${$rhash}{$key};
        $key .= ' ' while (length($key) < $min);
        prt("$key = [$val]\n");
    }
}

sub create_anon_funct($$$) {
    my ($rp,$clibR,$clibD) = @_;
    my $nf = sub { my $flag = shift;
          return $clibR if ($flag & 1);
          return $clibD; 
        };
     bless ($nf);
     ${$rp}{'PROJECT_USER_LIBS'} = $nf; # store the NEW function
}

# FIX20110421 - eliminate dupes in a sometimes very long set of libs, and libpaths...
sub eliminate_libpath_duplicates($) {
    my $libs = shift;
    my @arr = space_split($libs);
    my $nlibs = '';
    my %dupes = ();
    my ($lib);
    my %dups =();
    my $cnt = 0;
    foreach $lib (@arr) {
        if ( !defined $dupes{$lib} ) {
            $nlibs .= ' ' if (length($nlibs));
            $nlibs .= $lib;
            $dupes{$lib} = 1;
        } else {
            $cnt++;
            if (defined $dups{$lib}) {
                $dups{$lib}++;
            } else {
                $dups{$lib} = 1;
            }
        }
    }
    if ($dbg_s15 && ($libs ne $nlibs) && $cnt) {
        my @dup = sort keys(%dups);
        my $c2 = scalar @dup;
        prt("[15] eliminate_libpath_duplicates: [".join(' ',@dup)."]$c2, $cnt items REMOVED\n");
    }
    return $nlibs;
}

# FIX20110421 - eliminate dupes in a sometimes very long set of libs, and libpaths...
sub elim_the_lib_path_dupes($$) {
    my ($rlibR,$rlibD) = @_; # = \$clibR,\$clibD
    my $libR = eliminate_libpath_duplicates(${$rlibR});
    my $libD = eliminate_libpath_duplicates(${$rlibD});
    ${$rlibR} = $libR;
    ${$rlibD} = $libD;
}

# add any LDADD library dependant
# See 'LDADDS' but more usually prog_LDADD
# Need to later check _LIBADD and/or _DEPENDENCIES
# Check if is one of the 'built' libraries - only add it built?!?!
# NOTE key changes ($ky =~ s/-/_/g; and $ky =~ s/\./_/g; MAY APPLY here
sub check_for_LDADD($$$) {
    my ($rhash,$rp,$rparams) = @_;
    # my $roph = ${$rparams}{'REF_PROG_HASH'};
    my ($key,$val,@arr,$itm,$nm,$dir,$rel_path,$lpathD,$lpathR,$fnd,$fnd2,$nm2,$lib,$fnd3);
    my $libs = '';
    my $libD = '';
    my $libR = '';
    my $vals = '';
    my $auto_on = ${$rparams}{'CURR_AUTO_ON_FLAG'};  # = $auto_on_flag;
    my $proj_name = ${$rp}{'PROJECT_NAME'};
    $nm = '';
    $nm2 = '';
    my %dupes = ();
    my @libsarr = ();
    my @goodkeys = ();
    $fnd = 0;
    $fnd2 = 0;
    $fnd3 = 0;
    @arr = ();
    # 1 - search for MOST likely
    foreach $key (keys %{$rhash}) {
        if ($key =~ /^${proj_name}_/) {
            $val = ${$rhash}{$key};
            if ($key =~ /LDADD/) {
                $fnd++;
                push(@goodkeys,$key);
                $nm .= " $val";
            } elsif ($key =~ /LIBADD/) {
                $fnd2++;
                push(@goodkeys,$key);
                $nm2 .= " $val";
            } elsif ($key =~ /DEPENDENCIES/) {
                $fnd3++;
                push(@goodkeys,$key);
                $nm2 .= " $val";
            }
        }
    }
    if (@goodkeys) {
        prt("[15] Good keys for LDADD:$proj_name: Search dependencies...LD=$fnd LIB=$fnd2 DEP=$fnd3 keys[".join(" ",@goodkeys)."]\n [$nm] [$nm2]\n") if ($dbg_s15);
    } else {
        # no quite specific key found - do a general search
        foreach $key (keys %{$rhash}) {
            $val = ${$rhash}{$key};
            @arr = split(/\s+/,$val);
            $val = '';
            foreach $itm (@arr) {
                if (!defined $dupes{$itm}) {
                    $val .= ' ' if (length($val));
                    $val .= $itm;
                    $dupes{$itm} = 1;
                }
            }
            if ($key =~ /LDADD/) {
                $fnd++;
                push(@goodkeys,$key);
                $nm .= " $val" if (length($val));
            } elsif ($key =~ /LIBADD/) {
                $fnd2++;
                push(@goodkeys,$key);
                $nm2 .= " $val" if (length($val));
            } elsif ($key =~ /DEPENDENCIES/) {
                $fnd3++;
                push(@goodkeys,$key);
                $nm2 .= " $val" if (length($val));
            }
        }
        if ($fnd2 || $fnd3) {
            prt("General for LDADD:$proj_name: Search dependencies...LD=$fnd LIB=$fnd2 DEP=$fnd3 keys[".join(" ",@goodkeys)."]\n [$nm] [$nm2]\n");
            prtw("WARNING: Found dependency keys NOT HANDLED!\n");
        } else {
            prt("[15] General for LDADD:$proj_name: Search dependencies...LD=$fnd LIB=$fnd2 DEP=$fnd3 keys[".join(" ",@goodkeys)."]\n [$nm] [$nm2]\n") if ($dbg_s15);
        }
    }
    $fnd = 0;
    $nm = '';
    $nm2 = '';
    $libs = '';
    %dupes = ();
    foreach $key (@goodkeys) {
    #foreach $key (keys %{$rhash}) {
    #    if ($key =~ /LDADD/) {
            $fnd++;
            $val = ${$rhash}{$key};
            #@arr = split(/[\s|]/,$val);
            @arr = split(/[\s\|]+/,$val);
            prt("[15] $proj_name:$key: Checking [$val]...\n") if ($dbg_s15);
            foreach $itm (@arr) {
                next if ((length($itm) == 0)||($itm =~ /^\s+$/));
                $itm = path_u2d($itm);
                $itm =~ s/\\\\/\\/g while ($itm =~ /\\\\/);
                ($nm,$dir) = fileparse($itm);
                next if ((length($nm) == 0)||($nm =~ /^\s+$/));
                # ***TBD*** for the moment, avoid tha PAIN if it is just say an '@MATH_LIB@'
                # next if ($nm =~ /^\@(.*)\@$/);
                next if (is_macro_type($nm));
                next if ($nm =~ /^-/);  # like -lm, etc
                $vals .= ' ' if (length($vals));
                $vals .= $itm;
                $fnd2 = 0;
                $nm2 = $nm;
                $nm2 =~ s/-/_/g;
                $nm2 =~ s/\./_/g;
                $lib = '';
                if (defined ${$rparams}{'CURR_LIB_SUBS'}) {
                    my $ra = ${$rparams}{'CURR_LIB_SUBS'};
                    my ($v);
                    $v = scalar @{$ra};
                    # prt("Got $v hashes in array...finding [$nm] [$itm]\n");
                    foreach $v (@{$ra}) {
                        if (defined ${$v}{$nm}) {
                            $lib = ${$v}{$nm};
                            $fnd2 = 1;
                            last;
                        } elsif (defined ${$v}{$nm2}) {
                            $lib = ${$v}{$nm2};
                            $fnd2 = 2;
                            last;
                        }
                    }
                    if (!$fnd2) {
                        if ($dbg_s15) {
                            $v = scalar @{$ra};
                            prt("[15] Find FAILED! Got $v hashes in array...finding [$nm] or [$nm2] full [$itm]\n");
                            foreach $v (@{$ra}) {
                                foreach my $k (keys %{$v}) {
                                    my $v2 = ${$v}{$k};
                                    prt(" key [$k], with value [$v2]\n");
                                }
                            }
                        }
                    }
                } else {
                    prtw("WARNING: 'CURR_LIB_SUBS' NOT DEFINED! ie NO libraries built here!\n");
                }
                if (length($lib)) {
                    $lib =~ s/\.lib$//i;
                }
                if (length($lib)) {
                    if (!defined $dupes{$lib}) {
                        $dupes{$lib} = 1;
                        $libD .= ' ' if (length($libD));
                        $libR .= ' ' if (length($libR));
                        if ($auto_on & 2) {
                            $libD .= $lib.'D.lib';
                            $libR .= $lib.'.lib';
                        } else {
                            $libD .= $lib.'.lib';
                            $libR .= $lib.'.lib';
                        }
                        push(@libsarr,$lib);
                        $lib .= '.lib';
                        $libs .= ' ' if (length($libs));
                        $libs .= $lib;
                    }
                }
            }
#        }
    }

    if (length($libs)) {
        # this could have been established during the doing of the Library project(s)
        # ---------------------------------------------------------------------------
        if ($auto_on & 4) {
            $lpathD = "lib";
            $lpathR = "lib";
        } else {
            $lpathD = "Debug";
            $lpathR = "Release";
        }
        my $func = ${$rp}{'PROJECT_USER_LIBS'};
        my $clibR = $func->(1,$proj_name);  # get_user_libs - get Release
        my $clibD = $func->(2,$proj_name);  # get_user_libs - get NOT Release = Debug

        $clibR .= ' ' if (length($clibR));
        $clibR .= $libR;    # establish Release
        $clibR .= " /libpath:\"$lpathR\"";

        $clibD .= ' ' if (length($clibD));
        $clibD .= $libD;    # establish Debug
        $clibD .= " /libpath:\"$lpathD\"";
        elim_the_lib_path_dupes(\$clibR,\$clibD); # FIX20110421 - eliminate dupes in a sometimes very long set of libs, and libpaths...
        # create anonymous function
        create_anon_funct($rp,$clibR,$clibD);
        # MUST ADD DSW DEPENDENCY FOR THIS LOCALLY BUILT LIBRARY
        ${$rp}{'PROJECT_DEPENDS'} = [ @libsarr ];
        prt("[15] LDADD:$proj_name: Found and added [$libs] to get Rel:[$clibR], and Dbg:[$clibD]\n") if ($dbg_s15);
    } elsif ($fnd) {
        if (is_project_all_excluded($proj_name)) {
            prt("[15] :$proj_name: Dep keys $fnd found, but no value for this project, but it is EXCLUDED!\n") if ($dbg_s15);
        } else {
            prtw("WARNING:$proj_name: Dep keys $fnd found, but no value for this project!\n") if ($dbg_s15);
        }
    } else {
        prt("[15] :$proj_name: NO LDADD entry found in the ref HASH for project.\n") if ($dbg_s15);
    }
}

# else {    # !$use_output_change but if ($auto_on & 2) { # = $auto_on_flag
sub set_post_copy_action($$$) {
    my ($rp,$pn,$pt) = @_;
    my ($dnm,$rnm,$od,$dstg,$rstg,$dstgl,$rstgl,$od2);
    $dstgl = '';
    $rstgl = '';
    $od2 = '';
    if (($pt eq 'CA')||($pt eq 'WA')) {
        # these are EXE outputs to 'bin'
        $dnm = $pn."D.exe";
        $rnm = $pn.".exe";
        $od = 'bin';
        $rstg = "$rnm";
        $dstg = "$dnm";
    } elsif ($pt eq 'SL') {
        # these are LIB outputs to 'lib'
        $dnm = $pn."D.lib";
        $rnm = $pn.".lib";
        $od = 'lib';
        $rstg = "$rnm";
        $dstg = "$dnm";
    } elsif ($pt eq 'DLL') {
        # these are DLL outputs to 'bin'
        $dnm = $pn."D.dll";
        $rnm = $pn.".dll";
        $od = 'bin';
        $rstg = "$rnm";
        $dstg = "$dnm";

        # AND LIB outputs to 'lib'
        $dnm = $pn."D.lib";
        $rnm = $pn.".lib";
        $od2 = 'lib';
        $rstgl = "$rnm";
        $dstgl = "$dnm";
    } else {
        pgm_exit(1,"ERROR: INTERNAL: function 'set_new_user_outs' called with INVALID type [$pt]!\n");
    }
    $dnm = "$od;$rstg;$dstg;$od2;$rstgl;$dstgl";
    prt("Addition of post event [$dnm]\n") if (VERB9());
    ${$rp}{'PROJECT_POST_EVENT'} = $dnm;
    #prt("Keys in project hash...\n");
    #foreach $od (keys %{$rp}) {
    #    prt("$od "); # PROJECT_AM_RHASH PROJECT_USER_LIBS PROJECT_TYPE PROJECT_USER_OUTS PROJECT_NAME PROJECT_KEY
    #}
    #prt("\n");
    #pgm_exit(0,"TEMP EXIT");

}

sub set_new_user_outs($$$) {
    my ($rp,$pn,$pt) = @_;
    my ($dnm,$rnm,$od,$dstg,$rstg);
    if (($pt eq 'CA')||($pt eq 'WA')) {
        # these are EXE outputs to 'bin'
        $dnm = $pn."D.exe";
        $rnm = $pn.".exe";
        $od = 'bin';
        $rstg = "/out:\"".$od."\\".$rnm."\"";
        $dstg = "/out:\"".$od."\\".$dnm."\"";
    } elsif ($pt eq 'SL') {
        # these are LIB outputs to 'lib'
        $dnm = $pn."D.lib";
        $rnm = $pn.".lib";
        $od = 'lib';
        $rstg = "/out:\"".$od."\\".$rnm."\"";
        $dstg = "/out:\"".$od."\\".$dnm."\"";
    } elsif ($pt eq 'DLL') {
        # these are DLL outputs to 'bin'
        $dnm = $pn."D.dll";
        $rnm = $pn.".dll";
        $od = 'bin';
        $rstg = "/out:\"".$od."\\".$rnm."\"";
        $dstg = "/out:\"".$od."\\".$dnm."\"";

        # AND LIB outputs to 'lib'
        $dnm = $pn."D.lib";
        $rnm = $pn.".lib";
        $od = 'lib';
        $rstg .= " /implib:\"".$od."\\".$rnm;
        $dstg .= " /implib:\"".$od."\\".$dnm;
    } else {
        pgm_exit(1,"ERROR: INTERNAL: function 'set_new_user_outs' called with INVALID type [$pt]!\n");
    }

    my $func = sub { my $flag = shift;
        return $rstg if ($flag & 1);
        return $dstg;
    };
    bless ($func);
    ${$rp}{'PROJECT_USER_OUTS'} = $func;
}

# if ($auto_on & 32), scan the sources for headers
# -------------------------------------------------
sub enhance_with_headers($$$$$) {
    my ($rparams,$rsrcs,$rscans,$rdupes,$rp) = @_;
    my ($k2,$cnt,$tcnt,$ccnt,$file,$dir,$nam);
    my @allincs = ();
    my @allothers = ();
    my $dbg = 0;
    my $proj_name = ${$rp}{'PROJECT_NAME'}; # = $key
    $tcnt = scalar @{$rscans};
    prt("[15] $proj_name: Processing $tcnt sources, for headers...\n") if ($dbg_s15);    
    $ccnt = 0;
    my %done = ();
    my $rdh = \%done;
    my $line_cnt = 0;
    ${$rparams}{'TMP_DONE_HASH'} = $rdh;
    ${$rparams}{'TMP_LINE_TOTAL'} = $line_cnt;
    my $tot_cnt = 0;
    foreach $k2 (@{$rscans}) {
        $ccnt++;
        # prt("$ccnt of $tcnt: Scanning [$k2], got $cnt includes... ");
        #my $rih = full_src_scan($k2,$dbg,$rparams);
        #delete ${$rih}{$k2} if (defined ${$rih}{$k2});
        #my @arr = sort keys(%{$rih});
        recursive_src_scan($k2,$dbg,$rparams);
        if (! defined ${$rdh}{$k2}) {
            ${$rdh}{$k2} = 1;
            $tot_cnt++;
        }
        my @arr = keys(%{$rdh});
        $cnt = scalar @arr;
        $cnt -= $tot_cnt;
        prt("[15] $ccnt:$tcnt: From [$k2], $cnt items... [") if ($dbg_s15);
        $cnt = 0;
        foreach $file (@arr) {
            if (! defined ${$rdupes}{$file}) {
                if (is_h_source_extended($file)) {
                    ${$rdupes}{$file} = 1;
                    push(@allincs,$file);
                    $cnt++;
                    ($nam,$dir) = fileparse($file);
                    prt("$nam ") if ($dbg_s15);
                } else {
                    push(@allothers,$file);
                }
            }
        }
        prt("] added $cnt to list...\n") if ($dbg_s15);
        $tot_cnt += $cnt;
    }

    $line_cnt = ${$rparams}{'TMP_LINE_TOTAL'};
    ${$rparams}{'TOTAL_LINE_COUNT'} += $line_cnt;
    $cnt = scalar @allincs;
    if ($dbg_s15) {
        if ($cnt) {
            prt("[15] Got total includes $tot_cnt [");
            prt(join(" ",@allincs));
            prt("] from $line_cnt lines.\n");
        } else {
            prt("[15] Got NO additional includes, from $line_cnt lines.\n");
        }
    }

    $cnt = scalar @allincs;
    if ($cnt) {
        my $target_dir = ${$rparams}{'TARGET_DIR'};
        my $fix_relative_sources = ${$rparams}{'FIX_REL_SOURCE'};
        my ($rel_path,$rfil,$ff2,$ok,$fil,$msg);
        %done =();
        foreach $fil (@{$rsrcs}) {
            $done{$fil} = 1;
        }
        foreach $k2 (@allincs) {
            $fil = sub_root_dir($k2);
            if ($fix_relative_sources) {
                ($nam,$dir) = fileparse($k2);
                my $rel_path = get_rel_dos_path($dir,$target_dir);
                # ***TBD*** Could ensure this RELATIVE PATH is added to the project INCLUDES
                # ==========================================================================
                my $rfil = $rel_path.$nam;
                my $ff2 = $target_dir.$rfil;
                $ff2 = fix_rel_path($ff2);
                if (-f $ff2) {
                    $ok = "ok";
                } else {
                    $ok = "RELATIVE PROBLEM [$ff2]";
                }
                $msg = "rel [$fil] [$rfil] [$ff2] $ok ";
                $fil = $rfil;
            } else {
                if (-f $k2) {
                    $ok = "ok";
                } else {
                    $ok = "ERROR: CHECK ME!";
                }
                $msg = "root [$k2] [$fil] $ok ";
            }
            if (defined $done{$fil}) {
                $ok = 'ALREADY IN SOURCES!';
            } else {
                #########################################
                # This is what this is ALL about
                $ok = 'Added to sources.';
                push(@{$rsrcs},$fil);
                #########################################
            }
            prt("$msg $ok\n") if ($dbg_s15);
        }
    }
}

sub reprocess_the_lists($) {
    my ($rparams) = @_;
    my $auto_on = ${$rparams}{'CURR_AUTO_ON_FLAG'};  # = $auto_on_flag;
    my $r_progs  = ${$rparams}{'REF_PROGRAMS'};
    my $r_libs   = ${$rparams}{'REF_LIBRARIES'};
    # orginal Makefile.am scan hashes, if needed under same keys as above
    my $roph    = ${$rparams}{'REF_PROG_HASH'};
    my $rolh    = ${$rparams}{'REF_LIBS_HASH'};

    my ($ra,$inst,$tmp,$key,$val,$proj_name,$msg,$src,@srcs,$cnt,$rhash,$am_file);
    # check if no conflict of 'name' between LIBRARIES and PROGRAMS
    prt("\n[24] List of LIBRARIES and PROGRAMS being placed in individual \$rp HASH...\n") if ($dbg_s24);
    $tmp = scalar keys(%{$r_libs});
    prt("[24] LIST of $tmp LIBRARY keys...\n") if ($dbg_s24);
    $tmp = 0;
    foreach $key (sort keys %{$r_libs}) {
        $ra = ${$r_libs}{$key};
        $src = ${$ra}[0];; # get source list
        $inst = ${$ra}[1];
        $rhash = ${$rolh}{$key};
        $am_file = ${$rhash}{':_AM_FILE_SRC_:'};
        $msg = " [$key]";
        $proj_name = $key;
        @srcs = split(/\s+/,$src);
        $cnt = scalar @srcs;
        if ($auto_on & 2) { # = $auto_on_flag
            # modifying the library project name - should this be done???
			$proj_name = get_modified_library_name($proj_name);
        }
        $msg .= " [$proj_name]" if ($key ne $proj_name);
        $msg .= " sources: $cnt";
        $msg .= " am [$am_file]";
        prt("$msg [$inst]\n") if ($dbg_s24);
        foreach $val (keys %{$r_progs}) {
            if ($key eq $val) {
                prtw("WARNING: There is a duplication of the name [$key]\n");
                $tmp++;
            }
        }
    }

    $tmp = scalar keys(%{$r_progs});
    prt("[24] LIST of $tmp PROGRAM keys...\n") if ($dbg_s24);
    foreach $key (sort keys %{$r_progs}) {
        $ra = ${$r_progs}{$key};
        $src = ${$ra}[0]; # get source list
        $inst = ${$ra}[1];
        $rhash = ${$roph}{$key};
        $am_file = ${$rhash}{':_AM_FILE_SRC_:'};
        $msg = " [$key]";
        $proj_name = $key;
        @srcs = split(/\s+/,$src);
        $cnt = scalar @srcs;
        $msg .= " sources: $cnt";
        $msg .= " am [$am_file]";
        prt("$msg [$inst]\n") if ($dbg_s24);
    }
}

sub get_anon_proj_hash() {
    my %project = ();
    return \%project;
}

# 20120527 - do this with or without auot- on
# if ($auto_on & 2) { # = $auto_on_flag
# modifying the library project name - should this be done???
# ===========================================================
sub get_modified_library_name($) {
	my $org_name = shift;
    my $proj_name = $org_name;
	$proj_name =~ s/(\.|_)la//;
	# 20120302 - reverse this
	#if ( !($proj_name =~ /^lib/i) ) {
	#    $proj_name = 'lib'.$proj_name;
	#}
	$proj_name =~ s/_a$//;	# remove trailing '_a'
	if ($proj_name =~ /^lib(.+)$/i) {
		$proj_name = $1;
	}
    $proj_name = get_project_new_name($proj_name);  # my %proj_renaming = (); -m old:new
    prt("[v9] Library name MODIFIED from [$org_name] to [$proj_name]\n")
        if (($org_name ne $proj_name) && VERB9());
	return $proj_name;
}

# SUMMARY OUTPUTS
# ===============
# depends on the basic structure, for programs
# bin_PROGRAMS = hello
# hello_SOURCES = hello.c

#sub list_to_arrays($$$$) {
#    my ($in_fil,$rprogs,$rlibs,$ramsdone) = @_;
sub am_list_to_arrays($) {
    my ($rparams) = @_;
    # extract params
    my $in_fil = ${$rparams}{'AM_FILE'};
    my ($msg,$ra,$inst);
    if (! defined $in_fil) {
        $msg = "\n sub am_list_to_arrays called with in file ('AM_FILE') NOT defined";
        prtw("WARNING: Appears NO Makefile.am files to scan! $msg\n"); # 25/12/2010 - no 'Makefile.am'
        return;
    }
    if ((length($in_fil) == 0)||($in_fil =~ /^\s+$/)) {
        pgm_exit(1,"INTERNAL ERROR: 'AM_FILE' NOT correctly set in rparams!\n");
    }
    my $r_progs = ${$rparams}{'REF_PROGRAMS'};
    my $r_libs = ${$rparams}{'REF_LIBRARIES'};
    # orginal Makefile.am scan hashes, if needed under same keys as above
    my $roph = ${$rparams}{'REF_PROG_HASH'};
    my $rolh = ${$rparams}{'REF_LIBS_HASH'};
    my $auto_on = ${$rparams}{'CURR_AUTO_ON_FLAG'};  # = $auto_on_flag;

    my $ramsdone = ${$rparams}{'REF_AMS_DONE'};
    my $fix_relative_sources = ${$rparams}{'FIX_REL_SOURCE'};
    my $target_dir = ${$rparams}{'TARGET_DIR'};
    my $root_folder = ${$rparams}{'ROOT_FOLDER'};
    my ($in_tit,$in_dir) = fileparse($in_fil);
    my %my_src_hash = ();
    my $rsh = \%my_src_hash;
    my %projects_hash = ();
    my $rph = \%projects_hash;
    #my @msvc_c_files = ();
    #my @msvc_h_files = ();
    my @c_files = ();
    my @h_files = ();
    my $am_cnt   = scalar keys(%{$ramsdone});
    my $prog_cnt = scalar keys(%{$r_progs});
    my $libs_cnt = scalar keys(%{$r_libs});
    if (($prog_cnt == 0) && ($libs_cnt == 0)) {
        if ($am_cnt == 1) {
            prt("Processed $am_cnt AM file, but NO programs nor libraries found. [$in_fil]\n");
        } else {
            prtw("\nWARNING: AM files processed yielded NO programs nor libraries! (in $am_cnt am files)\n");
        }
        # show targets, if any

        return $rsh;
    }
    my $prog_cnt2 = 0;
    my $lib_cnt2 = 0;
    my $total_sources = 0;
    my $source_missed = 0;
    my $found_count = 0;
    # ====================================================================================
    # This is also the SUMMARY, and check if source found, or NOT
    # set my $total_sources = 0; and my $source_missed = 0;
    my ($key, $val, @av, $fil);
    my ($src, $tit, $dir, $ext, $cnt, $ok, $ff, $rfil);
    my ($ff2,$ok2,@arr,$k2,$v2,$am_file,$sam_file);
    my (@av2,$tmp2);
    my @done = ();
    #my $sgrp = get_def_src_grp();    # "Source Files";
    #my $sflt = get_def_src_filt();
    #my $hgrp = get_def_hdr_grp();    # "Header Files";
    #my $hflt = get_def_hdr_filt();
    my $rel_path = '';
    if ($fix_relative_sources) {
        $rel_path = get_rel_dos_path($in_dir,$target_dir);
        prt("Got relative [$rel_path], from in [$in_dir], and targ [$target_dir]\n");
    }
    my ($rhash,$proj_name,$proj_type,$tmp,$addsrcs);    # original HASH of Makefile.am scan
    my %dupes = (); # avoid source duplications
    my $rlib_dupes = ${$rparams}{'REF_LIB_DUPES'}; # = \%lib_dupes;
    my %project_dupes = (); # key is simple file name, contents an array [$ff,$relfile]
    my @header_scans = ();

    reprocess_the_lists($rparams);

    # process LIBRARIES before PROGRAMS - may use this/these libaries in the programs
    $addsrcs = '';
    prt("\nAM files yielded the following library SOURCES... (from $am_cnt files)\n") if ($libs_cnt);
    foreach $key (sort keys %{$r_libs}) {
        next if ((length($key) == 0)||($key =~ /^\s+$/));   # ignore BLANKS
        $lib_cnt2++;
        $proj_name = $key;
        ###if ($auto_on & 2) { # = $auto_on_flag
        # modifying the library project name - should this be done??? YES - choose as DEFAULT
        $proj_name = get_modified_library_name($proj_name);
        ###}
        #my %project = ();
        #my $rp = \%project;
        my $rp = get_anon_proj_hash();
        my @srcs = ();
        # GET -T project:type[:source_list]
        $addsrcs = '';
        $proj_type = get_user_proj_type($proj_name,'SL',\$addsrcs);  # static library
        ${$rp}{'PROJECT_TYPE'} = $proj_type;
		${$rp}{'PROJECT_KEY'} = $key;
        ${$rp}{'PROJECT_NAME'} = $proj_name; # = $key
        ${$rp}{'PROJECT_USER_LIBS'} = ${$rparams}{'CURR_USER_LIBS'};  # get_user_libs
        ${$rp}{'PROJECT_USER_OUTS'} = ${$rparams}{'CURR_USER_OUTS'};  # normal fetch for 'out:puts'
        # my $rolh = ${$rparams}{'REF_LIBS_HASH'};
        pgm_exit(1,"ERROR INTERNAL: key [$key] NOT defined in ref REF_LIBS_HASH! WHY?\n") if (!defined ${$rolh}{$key} );
        $rhash = ${$rolh}{$key};    # extract from LIBRARY hash
        ${$rp}{'PROJECT_AM_RHASH'} = $rhash; # add to PROJECT hash
        $am_file = ${$rhash}{':_AM_FILE_SRC_:'};
        $sam_file = sub_root_dir($am_file);
        mark_in_dir_scan($rparams,$sam_file);
        ### show_scalar_ref_hash($rhash);
        # if the $key made it here with macros, then try to adjust the project name
        ###$val = ${$rlibs}{$key};
        $ra = ${$r_libs}{$key};
        $val = ${$ra}[0];
        $inst = ${$ra}[1];
        ${$rp}{'PROJECT_INST'} = $inst;
        @av = split(/\s/,$val);
        $cnt = scalar @av;
        prt("LIBRARY: [$key] [$inst] $cnt SOURCES: [".($dbg_s15 ? $am_file : $sam_file)."]\n");
        if ($proj_name =~ /[\@\$\s]/) {
            prtw("WARNING:L: ***TBD*** Project name contains space, \@ or \$ [$proj_name]! Potential problems?\n");
        }
        # 20120601 - ADD in any USER sources, like -A proj:srcs
        $tmp = get_added_srcs_4_proj($proj_name);
        if (length($tmp)) {
            @av2 = split(';',$tmp);
            $tmp2 = scalar @av2;
            prt("Adding $tmp2 user sources [$tmp] for project [$proj_name]\n");
            push(@av,@av2);
        } else {
            prt("[v9] No user sources for project [$proj_name]\n") if (VERB9());
        }

        if ($auto_on & 2) { # = $auto_on_flag
            if ($use_output_change) {
                set_new_user_outs($rp,$proj_name,$proj_type);
                $msg = "Bit: 2: key [$key], pn [$proj_name] [$proj_type] - fetch R:'";
                $msg .= ${$rp}{'PROJECT_USER_OUTS'}->(1,$proj_name);
                $msg .= "' D:'";
                $msg .= ${$rp}{'PROJECT_USER_OUTS'}->(2,$proj_name);
                $msg .= "'";
                prt("[15] $msg\n") if ($dbg_s15);
            } else {    # !$use_output_change but if ($auto_on & 2) { # = $auto_on_flag
                set_post_copy_action($rp,$proj_name,$proj_type);
            }
        } else {
            prt("[15] auto output is OFF\n") if ($dbg_s15);
        }
        # FIX20120528 - DO this ALWAYS
            if (! defined ${$rlib_dupes}{$proj_name}) {
                ${$rlib_dupes}{$proj_name} = 1;
                my %h = ();
                $h{$key} = $proj_name;
                ${$rparams}{'CURR_LIB_SUBS'} = [] if (!defined ${$rparams}{'CURR_LIB_SUBS'});
                $tmp = ${$rparams}{'CURR_LIB_SUBS'};
                push(@{$tmp}, \%h);
                prt("[15] Stored kv [$key] = [$proj_name], for inst [$inst] in 'CURR_LIB_SUBS' array\n") if ($dbg_s15);
            }
        #} else {
        #    prt("[15] auto output is OFF\n") if ($dbg_s15);
        #}

        @done = (); # clear DONE
        %dupes = (); # clear source dupes
        @header_scans = (); # clear to scan list
        foreach $fil (@av) {
            next if ((length($fil) == 0)||($fil =~ /^\s+$/));   # ignore BLANKS
            $ff = $in_dir.$fil;
            $ff = fix_rel_path3($ff,"list_to_arrays");
            next if (-d $ff);   # ignore DIRECTORIES
            $total_sources++;
            if (-f $ff) {
                $ok = "ok";
                push(@header_scans,$ff);
                $project_dupes{$ff} = 1;
            } else {
                if (is_c_source_extended($fil)) {
                    $ok = "*** LIB SOURCE NOT FOUND [$ff]";
                } else {
                    $ok = "not found [$ff]";
                }
                if ($find_bad_source) {
                    # do_dir_scan($root_folder,0) if (!$done_dir_scan);
                    @arr = ();
                    ($tit,$dir) = fileparse($fil);
                    $cnt = ac_is_file_in_scan($rparams,$tit,$dir,\@arr);
                    if ($cnt) {
                        $ff = $arr[0];  # for now take just the FIRST, but...
                        $ok = "ok - found $cnt";
                        $found_count++;
                        push(@header_scans,$ff);
                        $project_dupes{$ff} = 1;
                    }
                }
                if (!($ok =~ /^ok/)) {
                    $source_missed++;
                }
            }
            ($tit,$dir) = fileparse($ff);
            if ($fix_relative_sources) {
                $rel_path = get_rel_dos_path($dir,$target_dir);
                $rfil = $rel_path.$tit;
                $ff2 = $target_dir.$rfil;
                if (-f $ff2) {
                    $ok2 = "ok2";
                } else {
                    if ($ok eq 'ok') {
                        $ok2 = "RELATIVE PROBLEM [$ff2]";
                    } else {
                        $ok2 = '';
                    }
                }
                prt( " [15] rel [$rfil] [$fil] [$ff] $ok $ok2\n" ) if ($dbg_s15);
                $fil = $rfil;
            } else {
                prt( " [15] [$fil] $ok\n" ) if ($dbg_s15);
            }
            if (is_c_source_extended($fil)) {
                if (is_in_array($tit,@done)) {
                    prtw("Duplicate of libs src FILE TITLE [$tit] file [$fil]!\n" ) if ($show_dup_title);
                } else {
                    push(@done,$tit);
                }
                ###push(@msvc_c_files, $src);
                #push(@msvc_c_files, [$fil, $sgrp, $sflt]);
                push(@c_files, $fil);
            } else {
                ###push(@msvc_h_files, $src);
                #push(@msvc_h_files, [$fil, $hgrp, $hflt]);
                push(@h_files, $fil);
            }
            if (!defined $dupes{$fil}) {
                $dupes{$fil} = 1;
                push(@srcs,$fil);
            }
            #if (defined $project_dupes{$fil}) {
            #    $project_dupes{$fil}++;
            #} else {
            #    $project_dupes{$fil} = 1;
            #}
        }
        if (length($addsrcs)) {
            @av = split(/;/,$addsrcs);
            $cnt = scalar @av;
            prt( " [15] LIBRARY: Adding $cnt user defined sources\n") if ($dbg_s15);
            foreach $fil (@av) {
                if (!defined $dupes{$fil}) {
                    $dupes{$fil} = 1;
                    $total_sources++;
                    push(@srcs,$fil);
                    $ff = $target_dir.$fil;
                    $ff = fix_rel_path($ff);
                    if (-f $ff) {
                        $ok = "ok";
                        push(@header_scans,$ff);
                        $project_dupes{$ff} = 1;
                    } else {
                        $ok = "not found [$ff]";
                    }
                    prt( " [15] [$fil] $ok\n" ) if ($dbg_s15);
                    if (!($ok =~ /^ok/)) {
                        $source_missed++;
                    }
                }
            }
        }
        $cnt = scalar @srcs;
        if ($cnt) {
            # perhaps NOW would be a good time to search for 'missing' headers
            # that is scan the source given for headers.
            # 04/06/2012 - This is VERY BAD for cmake output, unless a LOT more was done 
            # about the location of the header, so also only if NOT get_write_cmake_files()!!!
            # NOTE: Search for 'include_HEADERS' done in 'am_extract_from_hash'
            enhance_with_headers($rparams,\@srcs,\@header_scans,\%project_dupes,$rp)
                if (($auto_on & 32) && !get_write_cmake_files()); # do enhance_with_headers()
            # ======================================================================
            # prt("Got $cnt sources for [$key]\n");
            $cnt = scalar @srcs;
        } else {
            prt("Got NO sources for LIBRARY [$key], [$proj_name], but NULL project created\n");
        }
        ${$rp}{'PROJECT_SOURCES'} = \@srcs;  # static library source
        ${$rph}{$key} = $rp;
    }

    # process PROGRAMS afer LIBRARIES - may use the libaries in these programs
    @header_scans = ();
    prt( "\nAM files yielded programs $prog_cnt... (from $am_cnt file)\n" ) if ($prog_cnt);
    foreach $key (sort keys %{$r_progs}) {
        next if ((length($key) == 0)||($key =~ /^\s+$/));   # ignore BLANKS
        $prog_cnt2++;
        $proj_name = $key;
        my @srcs = ();
        %dupes = (); # avoid duplications for this project
        #my %project = ();
        #my $rp = \%project;
        my $rp = get_anon_proj_hash();
        $addsrcs = '';
        # GET -T project:type[:source_list]
        $proj_type = get_user_proj_type($proj_name,'CA',\$addsrcs);  # console application
        ${$rp}{'PROJECT_TYPE'} = $proj_type;
        ${$rp}{'PROJECT_NAME'} = $key;
        ${$rp}{'PROJECT_USER_LIBS'} = ${$rparams}{'CURR_USER_LIBS'};  # get_user_libs
        ${$rp}{'PROJECT_USER_OUTS'} = ${$rparams}{'CURR_USER_OUTS'};  # normal fetch for 'out:puts'
        # my $roph = ${$rparams}{'REF_PROG_HASH'};
        pgm_exit(1,"ERROR INTERNAL: key [$key] NOT defined in ref REF_PROG_HASH! WHY?\n") if (! defined ${$roph}{$key} );
        $rhash = ${$roph}{$key}; # extract from PROGRAM hash
        ${$rp}{'PROJECT_AM_RHASH'} = $rhash; # add to PROJECT hash
        $am_file = ${$rhash}{':_AM_FILE_SRC_:'}; # get AM file name
        $sam_file = sub_root_dir($am_file);
        mark_in_dir_scan($rparams,$sam_file);
        ###show_scalar_ref_hash($rhash);
        # if the $key made it here with macros, then try to adjust the project name
        ###$val = ${$rprogs}{$key}; # get source list
        $ra = ${$r_progs}{$key};
        $val = ${$ra}[0];
        $inst = ${$ra}[1];
        ${$rp}{'PROJECT_INST'} = $inst; # like sbin_PROGRAMS, bin_PROGRAMS, noinst_LIBRARIES, ...
        @av = split(/\s/,$val);
        $cnt = scalar @av;
        # prt( "PROGRAM: [$key] $cnt SOURCES: [".($dbg_s15 ? $am_file : $sam_file)."]\n" );
        # 23/04/2012 - add if fully EXCLUDED
        $msg = "PROGRAM: [$key] [$inst] $cnt SOURCES: [".($dbg_s15 ? $am_file : $sam_file)."]";
        $msg .= " EXCLUDED" if (is_project_all_excluded($key));
        prt("$msg\n");
        if ($proj_name =~ /[\@\$\s]/) {
            prtw("WARNING:P: ***TBD*** Project name contains space, \@ or \$ [$proj_name]! Potential problems?\n");
        }
        # 20120601 - ADD in any USER sources, like -A proj:srcs
        $tmp = get_added_srcs_4_proj($proj_name);
        if (length($tmp)) {
            @av2 = split(';',$tmp);
            $tmp2 = scalar @av2;
            prt("Adding $tmp2 users sources [$tmp] for project [$proj_name]\n");
            push(@av,@av2);
        }
        if ($auto_on & 2) { # = $auto_on_flag
            if ($use_output_change) {
                set_new_user_outs($rp,$proj_name,$proj_type);
                $msg = "Bit: 2: key [$key], pn [$proj_name] [$proj_type] - fetch R:'";
                $msg .= ${$rp}{'PROJECT_USER_OUTS'}->(1,$proj_name);
                $msg .= "' D:'";
                $msg .= ${$rp}{'PROJECT_USER_OUTS'}->(2,$proj_name);
                $msg .= "'";
                prt("[15] $msg\n") if ($dbg_s15);
            } else {    # !$use_output_change but if ($auto_on & 2) { # = $auto_on_flag
                set_post_copy_action($rp,$proj_name,$proj_type);
            }
        }
        # 20150528 - Do LDADD dependency check ALWAYS
        # if ($auto_on & 4) { # = $auto_on_flag
            prt("[15] Check LDADD and add library dependence.\n") if ($dbg_s15);
            check_for_LDADD($rhash,$rp,$rparams);
        # }
        @done = (); # clear DONE
        %dupes = (); # clear source dupes for this project
        @header_scans = (); # clear to scan list
        $cnt = scalar @av;
        prt( "[15] Processing $cnt sources for [$proj_name]...\n") if ($dbg_s15);
        foreach $fil (@av) {
            next if ((length($fil) == 0)||($fil =~ /^\s+$/));   # ignore BLANKS
            $ff = $in_dir.$fil;
            $ff = fix_rel_path3($ff,"list_to_arrays");
            next if (-d $ff);   # ignore DIRECTORIES
            $total_sources++;
            if (-f $ff) {
                $ok = "ok";
                push(@header_scans,$ff);
                $project_dupes{$ff} = 1;
            } else {
                if (is_c_source_extended($fil)) {
                    $ok = "*** PROG SOURCE NOT FOUND [$ff]";
                } else {
                    $ok = "not found [$ff]";
                }
                if ($find_bad_source) {
                    #do_dir_scan($root_folder,0) if (!$done_dir_scan);
                    @arr = ();
                    ($tit,$dir) = fileparse($fil);
                    $cnt = ac_is_file_in_scan($rparams,$tit,$dir,\@arr);
                    if ($cnt) {
                        $ff = $arr[0];  # for now take just the FIRST, but...
                        $ok = "ok - found $cnt";
                        push(@header_scans,$ff);
                        $project_dupes{$ff} = 1;
                        if (!$fix_relative_sources) {
                            # but have the FULL PATH
                            ($tit,$dir) = fileparse($ff);
                            $rel_path = get_rel_dos_path($dir,$root_folder);
                            $fil = $rel_path.$tit;
                            $fil =~ s/^\.\\//;
                        }
                        $found_count++;
                    }
                }
                if (!($ok =~ /^ok/)) {
                    $source_missed++;
                }
            }
            ($tit,$dir) = fileparse($ff);
            if ($fix_relative_sources) {
                $rel_path = get_rel_dos_path($dir,$target_dir);
                $rfil = $rel_path.$tit;
                $ff2 = $target_dir.$rfil;
                if (-f $ff2) {
                    $ok2 = "ok2";
                } else {
                    if ($ok eq 'ok') {
                        $ok2 = "RELATIVE PROBLEM [$ff2]";
                    } else {
                        $ok2 = '';
                    }
                }
                prt( " [15] rel [$rfil] [$fil] [$ff2] $ok $ok2\n") if ($dbg_s15);
                $fil = $rfil;
            } else {
                prt( " [15] [$fil] $ok\n") if ($dbg_s15);
            }
            if ( is_c_source_extended($fil) ) {
                if ( is_in_array($tit,@done) ) {
                    prtw("Duplicate of prog FILE TITLE [$tit] file [$fil]!\n" ) if ($show_dup_title);
                } else {
                    push(@done,$tit);
                }
                #push(@msvc_c_files, $src);
                #push(@msvc_c_files, [$fil, $sgrp, $sflt]);
                push(@c_files, $fil);
            } else {
                #push(@msvc_h_files, $src);
                #push(@msvc_h_files, [$fil, $hgrp, $hflt]);
                push(@h_files, $fil);
            }
            if (!defined $dupes{$fil}) {
                $dupes{$fil} = 1;
                push(@srcs,$fil);
            }
        }
        # done the AM file sources - any USER sources to process?
        if (length($addsrcs)) {
            @av = split(/;/,$addsrcs);
            $cnt = scalar @av;
            prt( " [15] PROGRAM: Adding $cnt user defined sources\n") if ($dbg_s15);
            foreach $fil (@av) {
                if (!defined $dupes{$fil}) {
                    $dupes{$fil} = 1;
                    $total_sources++;
                    push(@srcs,$fil);
                    $ff = $target_dir.$fil;
                    $ff = fix_rel_path($ff);
                    if (-f $ff) {
                        $ok = "ok";
                        push(@header_scans,$ff);
                        $project_dupes{$ff} = 1;
                    } else {
                        $ok = "not found [$ff]";
                    }
                    prt( " [15] [$fil] $ok\n" ) if ($dbg_s15);
                    if (!($ok =~ /^ok/)) {
                        $source_missed++;
                    }
                }
            }
        }
        $cnt = scalar @srcs;
        if ($cnt) {
            enhance_with_headers($rparams,\@srcs,\@header_scans,\%project_dupes,$rp)
                if (($auto_on & 32) && !get_write_cmake_files()); # do enhance_with_headers()
            $cnt = scalar @srcs;
            # prt("Got $cnt sources for [$key]\n");
        } else {
            prt("Got NO sources for PROGRAM [$key], [$proj_name], but NULL project created\n");
        }
        ${$rp}{'PROJECT_SOURCES'} = \@srcs;  # console application source
        ${$rph}{$key} = $rp;
    }

    #$key = scalar @msvc_c_files;
    #$val = scalar @msvc_h_files;
    $key = scalar @c_files;
    $val = scalar @h_files;
    if ($key || $val || $prog_cnt2 || $lib_cnt2) {
        $ok = "Done AM file [$in_fil], ";
        $ok .= "and ".($am_cnt - 1)." more, " if ($am_cnt > 1);
        $ok .= "and found -";
        prt("$ok\n");
        prt("Set of $key C SOURCE files, and $val headers (and others)...for progs=$prog_cnt2, libs=$lib_cnt2\n" );
    }
    # hmmm, since this is the LAST output, perhaps not a warning
    prt("NOTE: $source_missed of total $total_sources sources were NOT FOUND! [$in_fil]\n") if ($source_missed);
    prt("NOTE: $found_count files were found by a full directory scan of [$in_dir].\n") if ($found_count);

    #${$rsh}{'C_SOURCES'} = [ @msvc_c_files ];
    #${$rsh}{'H_SOURCES'} = [ @msvc_h_files ];

    ${$rparams}{'REF_SOURCES_HASH'} = $rsh;
    ${$rparams}{'REF_PROJECTS_HASH'} = $rph;

    return $rsh;
}

sub am_mycmp_decend {
   return 1 if (${$a}[0] gt ${$b}[0]);
   return -1 if (${$a}[0] lt ${$b}[0]);
   return 0;
}

my @excluded_files = qw( mt.dep buildlog.htm ); 
my @excluded_exts = qw(.old .bak .obj .err .pdb .lst .pch .ilk 
.ncb .plg .opt .idb .aps .sbr .suo .exp .bsc .manifest .user 
.res .sdf .opensdf .tlog .ipch .zip .exe .lib .dll .exp ); 
my @excluded_dirs = qw( debug release ipch autom4te.cache m4 );
my @excluded_msvc = qw( .dsw .dsp .sln .vcproj .vcxproj .user .filters );
my @excluded_graphic = qw( .png .gif .jpg .jpeg .bmp .ppm .tiff .pgm .pbm );

sub in_excluded_files($) {
    my $fil = shift;
    my ($n,$d) = fileparse($fil);
    my ($txt);
    my $lc = lc($n);
    foreach $txt (@excluded_files) {
        return 1 if ($lc eq $txt);
    }
    return 0;
}

sub has_excluded_ext($) {
    my $fil = shift;
    my ($n,$d,$e) = fileparse( $fil, qr/\.[^.]*/ );
    my $lce = lc($e);
    my ($ext);
    foreach $ext (@excluded_exts) {
        return 1 if ($lce eq $ext);
    }
    return 0;
}

sub in_excluded_folder($) {
    my $fil = shift;
    my $lc = lc($fil);
    my ($dir);
    foreach $dir (@excluded_dirs) {
        return 1 if ($lc =~ /(\\|\/)$dir(\\|\/)/);
    }
    return 0;
}

sub has_excluded_msvc($) {
    my $fil = shift;
    my ($n,$d,$e) = fileparse( $fil, qr/\.[^.]*/ );
    my $lce = lc($e);
    my ($ext);
    foreach $ext (@excluded_msvc) {
        return 1 if ($lce eq $ext);
    }
    return 0;
}

sub has_graphic_ext($) {
    my $fil = shift;
    my ($n,$d,$e) = fileparse( $fil, qr/\.[^.]*/ );
    my $lce = lc($e);
    my ($ext);
    foreach $ext (@excluded_graphic) {
        return 1 if ($lce eq $ext);
    }
    return 0;
}
 


sub am_ignored_extent($) {
    my $fil = shift;
    return 1 if ($fil =~ /\.html$/i);
    return 1 if ($fil =~ /\.htm$/i);
    return 1 if ($fil =~ /\.po$/i);
    return 1 if ($fil =~ /\.gmo$/i);
    return 1 if ($fil =~ /\.sgml$/i);
    #return 1 if ($fil =~ /\.in$/);
    return 1 if ($fil =~ /(\\|\/)Makefile$/);
    # 20120419 - added the following
    return 1 if ($fil =~ /\.sh$/i);
    return 1 if (in_excluded_files($fil));
    return 1 if (has_excluded_ext($fil));
    return 1 if (in_excluded_folder($fil));
    return 1 if (has_excluded_msvc($fil));
    return 1 if (has_graphic_ext($fil));
    # some specials MSVC10
    return 1 if ($fil =~ /_manifest\.rc$/i);
    return 0;
}

# this is more a DIAGNOSTIC output
# ================================
sub am_out_dir_scan_info($) {
    my ($rparams) = @_;
    return if (! ${$rparams}{'CURR_DONE_SCAN'} );
    my $dir = ${$rparams}{'CURR_FILE_DIR'};
    my $rda = ${$rparams}{'CURR_DIR_SCAN'};
    my $targ_dir = ${$rparams}{'TARGET_DIR'};
    # ${$rp}{'PROJECT_TARGET'} = $target_dir;
    my $mslist = (defined ${$rparams}{'CURR_MISSED_SOURCES'}) ? ${$rparams}{'CURR_MISSED_SOURCES'} : ''; # = $missed_source_list
    my $msdsp = (defined ${$rparams}{'CURR_MISSED_SRCDSP'}) ? ${$rparams}{'CURR_MISSED_SRCDSP'} : ''; # = $missed_source_dsp
    my $cnt = scalar @{$rda};
    prt("\n");
    prt("[20] Checking $cnt files, from directory scan with those in DSP files... moment...\n") if ($dbg_s20);
    my ($i,$file,$fnd,$done,$sfil,$msg);
    my ($missedC, $missedCE, $missedH, $missedO);
    my ($snam,$sdir,$rel_path,$rfil,$dmsg,$ndir,$dupe,$ignored);
    $done = 0;
    $dupe = 0;
    $ignored = 0;
    $missedC  = 0;
    $missedCE = 0;
    $missedH  = 0;
    $missedO  = 0;
    my @cfil = ();
    my @cext = ();
    my @hext = ();
    my @coth = ();
    my @ignore = ();
    my %dupes = ();
    $msg = '';
    $dmsg = '';
    $ndir = '';
    for ($i = 0; $i < $cnt; $i++) {
        $fnd = ${$rda}[$i][2];
        if ($fnd) {
            $done++;
        } else {
            #$sfil = ${$rda}[$i][0];
            $file = ${$rda}[$i][1];  # get FULL FILE
            if ( defined $dupes{$file} ) {
                $dupe++;
            } else {
                $dupes{$file} = 1;
                $sfil = sub_root_folder($file);
                ($snam,$sdir) = fileparse($file);
                $rel_path = get_rel_dos_path($sdir,$targ_dir);
                $rfil = $rel_path.$snam;
                if (is_c_source($sfil)) {
                    $missedC++;
                    push(@cfil,[$file,$rfil,$sdir,$sfil]);
                } elsif (is_h_source_extended($file)) {
                    $missedH++;
                    push(@hext,[$file,$rfil,$sdir,$sfil]);
                } elsif (is_c_source_extended($sfil)) {
                    $missedCE++;
                    push(@cext,[$file,$rfil,$sdir,$sfil]);
                } else {
                    if (($file =~ /\\temp\\/)||(am_ignored_extent($file))) {
                        # these are in the 'temp' folder, or
                        # some html, sg
                        $ignored++;
                        push(@ignore,[$file,$rfil,$sdir,$sfil]);
                    } else {
                        $missedO++;
                        push(@coth,[$file,$rfil,$sdir,$sfil]);
                    }
                }
            }
        }
    }

    prt("STATS: DSP files have $done of total $cnt scan, missed $missedC C sources, $missedCE C extended, $missedH HEADER\n files, $missedO OTHERS, $ignored ignored, $dupe dupes...\n");

    # 20101014 - add a DSP like output
    my ($rarr);
    @cfil = sort am_mycmp_decend @cfil;
    @hext = sort am_mycmp_decend @hext;
    @cext = sort am_mycmp_decend @cext;
    @coth = sort am_mycmp_decend @coth;
    # ignore ignored output...
    if ($missedC) {
        $rarr = \@cfil;
        prt("[20] Missed $missedC C/C++ ...\n") if ($dbg_s20);
        $msg .= "\n# Missing $missedC C/C++ sources...\n";
        $dmsg .= "\n// Missing $missedC C/C++ sources...\n";
        $ndir = '';
        for ($i = 0; $i < $missedC; $i++) {
            $file = ${$rarr}[$i][0];
            $rfil = ${$rarr}[$i][1];
            $sdir = ${$rarr}[$i][2];
            $sfil = ${$rarr}[$i][3];
            prt(" Missed C/C++ [$sfil]\n") if ($dbg_s20);
            $msg .= "$sfil\n";

            $dmsg .= "\n// =============================\n// Missing in [$sdir] directory...\n// =============================\n" if ($ndir ne $sdir);
            $dmsg .= "# Begin Source File\n";
            $dmsg .= "\n";
            $dmsg .= "SOURCE=".add_dotrel_if_none($rfil)."\n";
            $dmsg .= "# End Source File\n";
            $ndir = $sdir;
        }
    }

    if ($missedH) {
        $rarr = \@hext;
        prt("[20] And $missedH HEADERS...\n") if ($dbg_s20);
        $msg .= "\n# Missing $missedH headers...\n";
        $dmsg .= "\n\n// Missing $missedH headers...\n";
        $ndir = '';
        for ($i = 0; $i < $missedH; $i++) {
            $file = ${$rarr}[$i][0];
            $rfil = ${$rarr}[$i][1];
            $sdir = ${$rarr}[$i][2];
            $sfil = ${$rarr}[$i][3];
            prt(" Missed Header [$sfil]\n") if ($dbg_s20);
            $msg .= "$sfil\n";

            $dmsg .= "\n// =============================\n// Missing in [$sdir] directory...\n// =============================\n" if ($ndir ne $sdir);
            $dmsg .= "# Begin Source File\n";
            $dmsg .= "\n";
            $dmsg .= "SOURCE=".add_dotrel_if_none($rfil)."\n";
            $dmsg .= "# End Source File\n";
            $ndir = $sdir;
        }
    }

    if ($missedCE) {
        $rarr = \@cext;
        prt("[20] And $missedCE Extended...\n") if ($dbg_s20);
        $msg .= "\n# Missing $missedCE Extended items...\n";
        $dmsg .= "\n\n// Missing $missedCE Extended items...\n";
        $ndir = '';
        for ($i = 0; $i < $missedCE; $i++) {
            $file = ${$rarr}[$i][0];
            $rfil = ${$rarr}[$i][1];
            $sdir = ${$rarr}[$i][2];
            $sfil = ${$rarr}[$i][3];
            prt(" Missed C/C++ extended [$sfil]\n") if ($dbg_s20);
            $msg .= "$sfil\n";

            $dmsg .= "\n// =============================\n// Missing in [$sdir] directory...\n// =============================\n" if ($ndir ne $sdir);
            $dmsg .= "# Begin Source File\n";
            $dmsg .= "\n";
            $dmsg .= "SOURCE=".add_dotrel_if_none($rfil)."\n";
            $dmsg .= "# End Source File\n";
            $ndir = $sdir;
        }
    }

    if ($missedO) {
        $rarr = \@coth;
        prt("[20] Plus $missedO OTHERS...\n") if ($dbg_s20);
        $msg .= "\n# Missing $missedO OTHER items...\n";
        $dmsg .= "\n\n// Missing $missedO OTHER items...\n";
        $ndir = '';
        for ($i = 0; $i < $missedO; $i++) {
            $file = ${$rarr}[$i][0];
            $rfil = ${$rarr}[$i][1];
            $sdir = ${$rarr}[$i][2];
            $sfil = ${$rarr}[$i][3];
            prt(" Missed OTHER [$sfil]\n") if ($dbg_s20);
            $msg .= "$sfil\n";

            $dmsg .= "\n// =============================\n// Missing in [$sdir] directory...\n// =============================\n" if ($ndir ne $sdir);
            $dmsg .= "# Begin Source File\n";
            $dmsg .= "\n";
            $dmsg .= "SOURCE=".add_dotrel_if_none($rfil)."\n";
            $dmsg .= "# End Source File\n";
            $ndir = $sdir;
        }
    }

    # ignore ignored output... but put the count...
    if ($ignored) {
        $rarr = \@ignore;
        prt("[20] Plus $ignored IGNORED, in '\\temp\\' folder, *.png, *.html, *.po, Makefile, etc...\n") if ($dbg_s20);
        $msg .= "\n# Plus $ignored IGNORED, in '\\temp\\' folder, *.png, *.html, *.po, Makefile, etc...\n";
    }

    prt("Would display 'missing' lists, $missedC, $missedH, $missedCE, if -d 220 was added to the command.\n\n") if (!$dbg_s20);

    # output a MISSING SOURCE FILE LIST
    if (length($mslist) && length($msg)) {
        write2file($msg,$mslist);
        prt("Written missed source list to [$mslist] file.\n");
    }
    if (length($msdsp) && length($dmsg)) {
        write2file($dmsg,$msdsp);
        prt("Written missed source list DSP like [$msdsp] file.\n");
    }
}

1;
# eof - lib_amscam.pl
