# ###########################################################################################
# NAME: amsrcs03.pl
# AIM: MAKE DSP FILES - Given a folder, trace the makefile.am files, collecting
# libraries, applications and sources. The process starts with scanning configure.ac (or .in)
# Show 'projects' found, and SHOW the sources of each.
# AND write a DSP file for each!!!
# While it confidently outputs a set of DSP files, and a DSW file, in
# complex cases these will not work very well, as it MISSES lots of includes, and libraries
# ================================
# 22/09/2010 - Suspended in favour of amsrcs04.pl
# 08/09/2010 - Another MASSIVE review - many, MANY CHANGES, including support for Makefile.in,
# when there is NO Makefile.am, immediate exit if no configure.ac found, many more user options, etc
# struggling between source directories - choose to suspend enhancement of this script
# and start a new amsrcs04.pl, done completely different!
# 10/02/2010 - Review of this script
# ONLY GENERATES TEMPORARY DSP FILE(S), and 'temp_list.dsw' if the option $write_temp_ds is set to 1
# Add DSP 'sources' relative to a $target_dir, Remove a warning about no GROUP
# 
# 2009-06-09 - change error exit to WARNING only, and continue processing
# 2009-05-09 - Add or ensure _CRT_SECURE_NO_DEPRECATE is added to defines
# 22/11/2008 - Problem, perhaps, in that it 'splits' fgfs into MANY libraries
# which is perhaps how it should be???
# Also see am2dsp[n].pl as well, which is the opposite, in that is COMBINES 
# everything, including 'test' and 'utilties' into ONE ... and puts ALL the objects
# into Debug or Release, which would NOT account for duplicates!
# Also scan the 'top' directory for ALL FILE,
# and show files NOT in a project
# Add projects NOT addressed by main configure.ac and makefile.am
# 17/11/2007 - geoff mclane - http://geoffair.net/mperl
#
# The process
#
# Read the configure.ac file, and build a set of contents
# and put inputs into @make_input_list, or @other_input_files
# which are then put in @input_files ... set $dgb20 to see list as processed
#
# Each @input_files, and later @other_inputs (makefile.am) is processed in process_am_file()
# Sources are added to @msvc_c_files in form 'Lib/Project | Source | Title'
# extract_am_project then separates these into $am_projects{$lib} .= ['|'.]$lsc;
#
# The %am_project's are shown by show_am_projects( $main_root_dir );
# Then the 'other' projects are shown - show_other_projects( $main_root_dir );
# and finally all source files found show_all_sources( "makefile.am set", $main_root_dir );
# 04/04/2008 - add read of sub-directory 'configure.ac' if present ...
# 22/11/2008 - add /GR to DSP, and removed all \r output
# ###########################################################################################
use strict;
use warnings;
use File::Basename;    # to split path into ($name, $dir) = fileparse($ff); or ($nm,$dir,$ext) = fileparse( $fil, qr/\.[^.]*/ );
use File::Spec; # File::Spec->rel2abs($rel); # we are IN the SLN directory, get ABSOLUTE from RELATIVE
use Cwd;
my $perl_dir = 'C:\GTools\perl';
unshift(@INC, $perl_dir);
require 'fgutils02.pl' or die "Unable to load fgutils02.pl ...\n";
require 'relative.pl' or die "Unable to load relative.pl ...\n";
require 'chkmain.pl' or die "Unable to load chkmain.pl ...\n";
require 'utils.pl' or die "Unable to load utils.pl ...\n";

# log file stuff
my ($LF);
my $pgmname = $0;
if ($pgmname =~ /(\\|\/)/) {
    my @tmpsp = split(/(\\|\/)/,$pgmname);
    $pgmname = $tmpsp[-1];
}
my $outfile = $perl_dir."\\temp.$pgmname.txt";
open_log($outfile);
my $pack = $pgmname;

# Options
my $use_current_dir = 1;    # if NOT input directory given, use current
my $show_all_sources = 0;
my $show_missed_sources = 0;
my $load_log = 0; # load logfile into notepad at end
my $support_makefile_in = 0;
my $only_dry_run = 0;
my $exit_bogus_macro = 0;

my $main_root_dir = '';
my $target_dir = '';

# features
my $abort_on_ac_config = 0; # we do NOT care about this 'mistake' ;=))
my $error_comment_saw_bk = 0; # am_line_error ($aln, "comment following trailing backslash") if $saw_bk;
my $abort_on_conditional = 0; # complicated issue unresolved, but continuing anyway...

my $add_CRT_SECURE_NO_DEPRECATE = 1;
my $add_NOMINMAX = 1;
#my $add_SOURCE_REL = 0;
#my $src_relative = "..\\..";
my $add_CONFIG_H = 1;

my $recheck_am = 0;    # a debug RE-CHECK of makefile.am files for a reference
my $check_full = 1;    # check for the FULL file name
my $min_line = 60;
my $check4main = 1;    # check if the NOT FOUND modules have a main() service
my $check4main2 = 1;    # check if the source has a main() service
my $show_main = 0;        # actually SHOW the main
my $show_cond = 0;        # actually SHOW the condition for main
my $add_rel_src = 1;    # add the relative source to output
my $temp_in_file = '';  # $perl_dir."\\tempmfin.txt";
my $temp_in_macs = '';  # $perl_dir."\\tempinmac.txt";
my $write_temp_ds = 1;  # this is MEANT to be ON, and the following BAT do the COPY job
my $temp_upd_bat = $perl_dir."\\tempupd3.bat";
###############################

####### ONLY DSP STUFF ########
my $out_dsp  = 1;    # output a MAIN DSP and DSW files
my $out_dsp2 = 1;    # output a secondary DSP files

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

my $msvc_cflags = '';    # see %am_includes and %am_cppflags # hash by project, the CPPFLAGS, if ANY
my $msvc_libs   = '';    # see %am_libadds  = ();    # hash by project, the LDADD, if ANY
my $msvc_dlibs  = '';
my $msvc_rlibs  = '';
my $last_project = '';
my $last_dsp_file = '';
my @dspinfo = ();
############################

######################
# constants
my $IGNORE_PATTERN = "^##([^#].*)?\$";
my $WHITE_PATTERN = "^[ \t]*\$";
my $COMMENT_PATTERN = "^#";
my $RULE_PATTERN = "^([\$a-zA-Z_.][-.a-zA-Z0-9_(){}/\$]*) *:([^=].*|)\$";
my $SUFFIX_RULE_PATTERN = "^\\.([a-zA-Z]+)\\.([a-zA-Z]+)\$";
# like say bin_PROGRAMS = abc xyz
my $MACRO_PATTERN = "^([A-Za-z][A-Za-z0-9_]*)[ \t]*([:+]?)=[ \t]*(.*)\$";
# In *.in files, can find '@ON_WINDOWS@LINK = $(CC) $(LDFLAGS) -I. -I$(top_srcdir) -L.libs'
my $BOGUS_MACRO_PATTERN = "^([^ \t]*)[ \t]*([:+]?)=[ \t]*(.*)\$";
my $IF_PATTERN = "^if[ \t]+\([A-Za-z][A-Za-z0-9_]*\)[ \t]*\(#.*\)?\$";
my $ELSE_PATTERN = "^else[ \t]*\(#.*\)?\$";
my $ENDIF_PATTERN = "^endif[ \t]*\(#.*\)?\$";
my $PATH_PATTERN='(\\w|/|\\.)+';
# This will pass through anything not of the prescribed form.
my $INCLUDE_PATTERN = "^include[ \t]+((\\\$\\\(top_srcdir\\\)/${PATH_PATTERN})|(\\\$\\\(srcdir\\\)/${PATH_PATTERN})|([^/\\\$]${PATH_PATTERN}))[ \t]*(#.*)?\$";

my $AM_CONDITIONAL_PATTERN = "AM_CONDITIONAL\\((\\w+)";
my $AM_INIT_AUTOMAKE = "AM_INIT_AUTOMAKE\\(([^,]+),[ \t]*([^)]+)";

my %ac_macro_skip = (
    'AC_CHECK_HEADERS' => 1,
    'AC_CHECK_HEADER' => 2,
    'AC_HELP_STRING' => 3,
    'AC_DEFUN' => 4,
    'AC_EGREP_CPP' => 5,
    'AC_CHECK_FUNC' => 6,
    'PKG_CHECK_MODULES' => 7,
    'AC_CHECK_LIB' => 8,
    'AC_ARG_ENABLE' => 9,
    'AC_ARG_WITH' => 10
);

#### type constants
my $TYPE_NONE = 0;
my $TYPE_C    = 1;
my $TYPE_H    = 2;
my $TYPE_DSW  = 3;
my $TYPE_SLN  = 4;
my $TYPE_AM   = 5;
my $TYPE_MAK  = 6;

######################
# program variables
my $exit_status = 0;
my $cmd_line = '';
my @input_files = ();
my @make_input_list = ();
my @other_input_files = ();
my %output_files = ();
my %make_list = ();
my %am_vars = ();
my %def_type = ();
my @excluded_dirs = ();
my @var_list = ();
my $dsp_package = '';
my $dsp_version = '';
my %configure_cond = ();
my %configure_vars = ();
my %cfg_defines = ();
my @config_fullnames = ();
my @config_names = ();
my @config_headers = ();
my $config_header_line = '';
####my $am_file = '';
my @msvc_c_extra = ();
my @msvc_h_extra = ();
my @msvc_o_extra = ();
my @done_am = ();    # list of AM files read
my @ac_scanned = ();
my %config_ac_macros = ();
my %inc_hash = ();

# These two variables are used when generating each Makefile.in.
# They hold the Makefile.in until it is ready to be printed.
my $output_vars = '';
my $output_trailer = '';
# This holds the contents of a Makefile.am, as parsed by
# read_am_file.
my %contents = ();
# This holds the names which are targets.  These also appear in
# %contents.
my %targets = ();
# For a variable or target which is defined conditionally, this
# holds an array of the conditional values.  The array is composed
# of pairs of condition strings (the variables which configure
# will substitute) and values (the value of a target is
# meaningless).  For an unconditional variable, this is empty.
my %conditional = ();
# This holds the line numbers at which various elements of
# %contents are defined.
my %content_lines = ();
# This holds a 1 if a particular variable was examined.
my %content_seen = ();
# This is the conditional stack.
my @conditional_stack = ();
# This holds the set of included files.
my @include_stack = ();
# This holds the "relative directory" of the current Makefile.in.
# Eg for src/Makefile.in, this is "src".
my $relative_dir = '';
# This maps the source extension of a suffix rule to its
# corresponding output extension.
my %suffix_rules = ();
# per AM file sources
my @am_c_files = ();
my @am_h_files = ();
my @am_o_files = ();

#################
### final source lists
my @msvc_c_files = ();
my @msvc_titles  = ();
my @msvc_h_files = ();
my @msvc_o_files = ();
my %other_projs = ();   # store C/C++ sources under project names
my %other_deps = ();    # and store LIBRARY dependencies ..._LDADD, under project names
my %am_projects = ();   # store C/C++ sources under project names
my %am_headers = ();   # store H sources under project names
my %am_includes = ();    # hash by project, the INCLUDES, if ANY
my %am_cppflags = ();    # hash by project, the CPPFLAGS, if ANY
my %am_libadds  = ();    # hash by project, the LDADD, if ANY
my @all_files = ();
my $active_am_file = '';
my $current_am_file = '';
my $next_am_file = '';
my ($full_fil_path);
my @dspprojs = ();      # list of PROJECTS created

my @inf = ();
my @other_inputs = ();
#    if (is_c_source($f)) {
my $tot_c_sources = 0; # return $TYPE_C;
#    } elsif (is_h_source($f)) {
my $tot_h_sources = 0; # return $TYPE_H;
#    } elsif (is_dsw_file($f)) {
my $tot_dsw_sources = 0; # return $TYPE_DSW;
#    } elsif (is_sln_file($f)) {
my $tot_sln_sources = 0; # return $TYPE_SLN;
#    } elsif ($f =~ /^Makefile\.(am|in)$/i) {
my $tot_am_files = 0; # return $TYPE_AM;
#    } elsif ($f =~ /makefile/i) {
my $tot_mk_files = 0; #    return $TYPE_MAK;
my $tot_others = 0; # return $TYPE_NONE;
my %missed_exts = ();
my ($c_cnt,$t_cnt,$h_cnt,$o_cnt,$p_cnt);
my $act_am_ext = '';    # need to deal with Makefile.in slightly differently to get sources
my $act_am_file = '';
my $act_am_dir = '';
my %discarded = ();
my $act_rel_directory = '';
my @copy_bat = ();  # set of COPIES to be done, via a BATCH file
my $final_message = '';

my %incompete_macs = ();
my %undefined_macs = ();

my %content_by_file = ();

# warnings
my @warnings = ();
my %warned_items = ();
my $show_all_warns = 0;   # show ALL warnings as they happen...

my $cwd = cwd();
my $os = $^O;

my %IN_MACS = (
'BUILD_EXEEXT' => 'exe',
'BUILD_OBJEXT' => 'obj',
'CC' => 'cl',
'CC_FOR_BUILD' => 'cl',
'CFLAGS' => '',
'CFLAGS_FOR_BUILD' => '',
'CXX' => 'cl',
'CXXFLAGS' => '',
'CXXFLAGS_FOR_BUILD' => '',
'CXXLDFLAGS' => '',
'CXX_FOR_BUILD' => '',
'EBCDIC' => '',
'EXEEXT' => 'exe',
'HAVE_CPP' => '',
'INSTALL' => '',
'INSTALL_DATA' => '',
'LDFLAGS' => '',
'LIBTOOL' => 'link',
'LINK_SIZE' => '',
'MATCH_LIMIT' => '',
'MATCH_LIMIT_RECURSION' => '',
'MAYBE_CPP_TARGETS' => '',
'NEWLINE' => '',
'NOT_ON_WINDOWS' => '',
'NO_RECURSE' => 'no',
'OBJEXT' => 'obj',
'ON_WINDOWS' => '',
'PCRE_CPPLIB_VERSION' => '',
'PCRE_LIB_VERSION' => '',
'PCRE_POSIXLIB_VERSION' => '',
'POSIX_LIB' => '',
'POSIX_LOBJ' => '',
'POSIX_MALLOC_THRESHOLD' => '',
'POSIX_OBJ' => '',
'SHELL' => 'sh',
'UCP' => '',
'UTF8' => '',
'WIN_PREFIX' => '',
'bindir' => '',
'exec_prefix' => '',
'includedir' => '$(includedir)',
'libdir' => '',
'mandir' => '',
'prefix' => '',
'top_srcdir' => '$(top_srcdir)'
);

#######################
# debug - should be ALL OFF for release
my $debug_on = 0;
my $def_in_dir = 'C:\Projects\Jack';
my $dbg01 = 0; # show EACH configure.ac line
my $dbg02 = 0; # show "Storing configure_cond key $1 ... value=? ..."
my $dbg03 = 0; # show "Substute $key=$nval ... setting $var_hash{$key} = $nval;
my $dbg04 = 0; # show "Got ac_output_line = [$ac_output_line] ...
my $dbg05 = 0; # show "Adding $input [$ff] to make_input_list ...
my $dbg06 = 0; # list Makefile list found
my $dbg07 = 0; # show each 'makefile' processed ...
my $dbg08 = 0; # show "Group set to [$group] ... *AND* "Expanding variable $varname ...
my $dbg09 = 0; # show "Added [$file] to C EXTRA list...
my $dbg10 = 0; # show each makefile.am line ...
my $dbg11 = 0; # show "NO contents for [$last_var_name]! ...
my $dbg12 = 0; # show "End $last_var_name = ["... if !$saw_bk
my $dbg13 = 0; # show "Found if $1, and condition is TRUE (see cfg_defines) ...
my $dbg14 = 0; # show "Found a macro definition. 1[$1] 2[$2] 3[$3] ... something=something in Makefile.am
my $dbg15 = 0; # show macro "NB: [$last_var_name] = [$contents{$last_var_name}]" . ...
my $dbg16 = 0; # show "$pack: reading $am_file ...
my $dbg17 = 0; # show "Sources ending in .$source_suffix become .$object_suffix ...
my $dbg18 = 0; # show "Add $src to C list
my $dbg19 = 0; # show %contents after makefile.am parse
my $dbg20 = 0; # show "\nProcessing [$am_file] from input_files array ...
my $dbg21 = 0; # show "Project: [$proj] - sources [$srcs] ...
my $dbg22 = 0; # NOT PRESENTLY USED
my $dbg23 = 0; # show directory content count - "Found ".scalar @dir_cont." items in [$fil]
my $dbg24 = 0; # show "Processing AM file [" . $makefile . ".am]
my $dbg25 = 0; # show "Got INCLUDES [$incs] ...
my $dbg26 = 0; # show "For $group, saved INCLUDES [$incs]
my $dbg27 = 0; # show checking for substitution macros ...
my $dbg28 = 0; # show ALL %contents ... see $dbg19 also above to show more ...
# that is show like "CT: Got $cnt items in \%contents ... file $file_am ...
my $dbg29 = 0; # prt("[dbg_29] Found dependencies [$uproj]=[$srcs].\n") if ($dbg29);
my $dbg30 = 0; # prt( "[dbg30] Ending last DSP - [$fil] ...\n" ) if ($dbg30);
my $dbg31 = 0; # show if (/$AM_CONDITIONAL_PATTERN/o) { prt( "$aclnnum: [$acline]\n" ) if ($dbg31);
my $dbg32 = 0; # show "MACRO [$key]=[$nval]
my $dbg33 = 0; # show "Group set to [$group] ...
my $dbg34 = 0; # out warning that avoided re-read of *ac file
my $dbg35 = 0; # trace EACH if statement in read_am_file
my $dbg36 = 0; # show uncased lines, assume to be 'rule continuation' in makefile.[am|in] scan
my $dbg37 = 0; # show shell actions, in macro substitution
my $dbg38 = 0; # prt(" [dbg38] $key = [$nval], changed from [$cline]\n") if ($dbg38); and more...
my $dbg39 = 0; # For Makefile.in, show target separations... noisy...
my $dbg40 = 0; # Show project source lists...
my $dbg41 = 0; # prt("[dbg41] add_2_new_source_list: [$line] grp=[$grp], rel=[$sfil]\n") if ($dbg41);
my $dbg42 = 0; # prtw( "WARNING:others:[dbg42] [$sf] [$s] ALREADY IN inc_hash!\n" ) if ($dbg42);
my $dbg43 = 0; # show sifting of comments out of file lines
my $dbg44 = 0; # show sifting of 'include' out of file lines
my $dbg45 = 0; # prtw("WARNING:[dbg45] Using a LOOSE search, since [$proj] nor [$proj2]_SOURCES NOT FOUNT!\n") if ($dbg45);
my $dbg46 = 0; # prt("[dbg46] Added to contents:1: [$value]\n") if ($dbg46);
my $dbg47 = 0; # if ($dgb47) { foreach $input (@make_input_list) { prt $input = [$make_list{$input}]
my $dbg48 = 0; # debug sub try_for_substitution($$$$) { ... }

# Normally it was intended to read an am2cfg.def file, but set some anyway

$cfg_defines{"HAVE_GLUT"} = 1;
$cfg_defines{"HAVE_THREADS"} = 1;

# forward references
sub get_top_files($$);

# FUNCTIONS
# =====================================================
# debug

my $dbg_base = 'dbg';

sub set_dbg_base($) { $dbg_base = shift; }

sub get_dbg_var($) {
    my $val = shift;
    my $var = $dbg_base;
    my $res = -1;
    if ($val < 10) {
        $var .= "0$val";
    } else {
        $var .= "$val";
    }
    # from : http://perldoc.perl.org/functions/eval.html
    if (eval "defined \$$var") {
        $res = eval "\$$var";
    }
    return $res;
}

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

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

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

sub clear_dbg_var($) {
    my $val = shift;
    my $var = $dbg_base;
    if ($val < 10) {
        $var .= "0$val";
    } else {
        $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 set_all_dbg_on() {
    my ($i,$res);
    for ($i = 1; ;$i++) {
        $res = set_dbg_var($i);
        last if (!$res);
    }
    $show_all_warns = 1;   # show ALL warnings as they happen...
}

sub set_all_dbg_off() {
    my ($i,$res);
    for ($i = 1; ;$i++) {
        $res = clear_dbg_var($i);
        last if (!$res);
    }
    $show_all_warns = 0;   # show only NEW warnings...
}

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

# general
sub repeat_dsp_info() {
    if (@dspinfo) {
        prt( "\nRepeat show of ".scalar @dspinfo." lines of DSP info ...\n" );
        foreach my $di (@dspinfo) {
            prt("$di\n");
        }
    }
}

sub prtw($) {
    my ($wm) = shift;
    prt($wm) if ($show_all_warns);   # show ALL warnings as they happen...
    $wm =~ s/\n$//;
    if ( !defined $warned_items{$wm} ) {
        # but only KEEP if NOT a duplicate
        push(@warnings,$wm);
        $warned_items{$wm} = 1;
        prt("$wm\n") if (!$show_all_warns);   # show ONLY NEW warnings...
    }
}

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

sub pgm_exit($$) {
   my ($val,$msg) = @_;
   if (@warnings) {
      prt( "\nREPEAT OF ".scalar @warnings." WARNINGS ...\n" );
      foreach my $mg (@warnings) {
         prt("$mg\n");
      }
      prt("\n");
   } else {
      prt("No WARNINGS issued...\n") if ($val);
   }
   prt("Commands: [$cmd_line]\n");
   if (length($msg)) {
      $msg .= "\n" if (! ($msg =~ /\n$/) );
      prt($msg);
   }
   $msg = get_dbg_stg();
   prt( "Debug ON: $msg\n" ) if (length($msg));
   repeat_dsp_info();   # show the DSP/DSW files written - the whole purpose ;=))
   prt($final_message) if (length($final_message));
   close_log($outfile,$load_log);
   exit($val);
}

sub subract_target_dir($) {
   my ($fil) = shift;
   my $td = $target_dir;
   my $len = length($fil);
   if ($len > length($td)) {
      $len = length($td);
      my ($i);
      for ($i = 0; $i < $len; $i++) {
         last if (substr($td,$i,1) ne substr($fil,$i,1));
      }
      $fil = substr($fil,$i);
      $fil =~ s/^(\\|\/)//;
   }
   return $fil;
}

sub subract_source_dir($) {
   my ($fil) = shift;
   my $td = $act_rel_directory;
   my $len = length($fil);
   if ($len > length($td)) {
      $len = length($td);
      my ($i);
      for ($i = 0; $i < $len; $i++) {
         last if (substr($td,$i,1) ne substr($fil,$i,1));
      }
      $fil = substr($fil,$i);
      $fil =~ s/^(\\|\/)//;
   }
   return $fil;
}


sub does_next_am_file_exist($) {
    my $fil = shift;
    return 1 if (-f $fil);
    return 1 if (-f $fil.'.am');
    return 1 if ($support_makefile_in && (-f $fil.'.in'));
    return 1 if (-f $main_root_dir.$fil.'.am');
    return 1 if ($support_makefile_in && (-f $main_root_dir.$fil.'.in'));
    return 0;
}

sub get_next_am_file($$) {
    my ($fil,$caller) = @_;
    return $fil if (-f $fil);
    return $fil if (-f $fil.'.am');
    return $fil if ($support_makefile_in && (-f $fil.'.in'));
    return $fil if (-f $main_root_dir.$fil.'.am');
    return $fil if ($support_makefile_in && (-f $main_root_dir.$fil.'.in'));
    if ($support_makefile_in) {
        pgm_exit(1,"ERROR:gnf:$caller: [$fil], nor [.am], NOR [.in] DOES NOT EXIST! WHY ARE WE HERE!\n");
    } else {
        pgm_exit(1,"ERROR:gnf:$caller: [$fil], nor [.am] DOES NOT EXIST! WHY ARE WE HERE!\n");
    }
}

sub get_next_full_am_file($) {
    my $fil = shift;
    my $nfil = $fil;
    if (-f $main_root_dir.$fil.'.am') {
        $nfil = $main_root_dir.$fil.'.am';
    } elsif ($support_makefile_in && (-f $main_root_dir.$fil.'.in')) {
        $nfil = $main_root_dir.$fil.'.in';
    } elsif (-f $fil.'.am') {
        $nfil = $fil.'.am';
    } elsif ($support_makefile_in && (-f $fil.'.in')) {
        $nfil = $fil.'.in' ;
    } elsif (-f $fil) {
        $nfil = $fil; # already GOT name
    } else {
        if ($support_makefile_in) {
            pgm_exit(1,"ERROR:gnff: [$fil], nor [.am], NOR [.in] DOES NOT EXIST! WHY ARE WE HERE!\n");
        } else {
            pgm_exit(1,"ERROR:gnff: [$fil], nor [.am] DOES NOT EXIST! WHY ARE WE HERE!\n");
        }
    }
    return path_u2d($nfil); # always return the DOS form
}

sub is_if_else_endif($) {
    my ($txt) = shift;
    $txt = trim_all($txt);
    return 1 if ($txt =~ $IF_PATTERN); # = "^if[ \t]+\([A-Za-z][A-Za-z0-9_]*\)[ \t]*\(#.*\)?\$";
    return 1 if ($txt =~ $ELSE_PATTERN); # = "^else[ \t]*\(#.*\)?\$";
    return 1 if ($txt =~ $ENDIF_PATTERN); # = "^endif[ \t]*\(#.*\)?\$";
    return 2 if ($txt =~ /^if\s+/);
    return 2 if ($txt =~ /^elif\s+/);
    return 2 if ($txt =~ /^else\s*/);
    return 2 if ($txt =~ /^endif\s*/);
    return 3 if ($txt =~ /^test\s+/);
    return 4 if ($txt =~ /^echo\s+/);
    return 0;
}



sub get_my_type_stg($) {
    my $typ = shift;
    if ($typ == $TYPE_C) {
        return "C/C++";
    } elsif ($typ == $TYPE_H) {
        return "Headr";
    } elsif ($typ == $TYPE_DSW) {
        return "Dsw/p";
    } elsif ($typ == $TYPE_SLN) {
        return "VCSln";
    } elsif ($typ == $TYPE_AM) { # /^Makefile\.(am|in)$/i)
        return "Mk_AM"; # $tot_am_files = 0; # return $TYPE_AM;
    } elsif ($typ == $TYPE_MAK) { # $f =~ /makefile/i)
        return "MakeF";
    }
    return "NoGrp"; # my $tot_others = 0; # return $TYPE_NONE;
}

sub has_no_extent($) {
    my ($fil) = shift;
    my ($fnm, $fdir, $fe) = fileparse( $fil, qr/\.[^.]*/ );
    if (length($fe) == 0) {
        return 1;
    }
    return 0;
}

# specific
sub exclude_cvs_svn($) {
    my ($dir) = shift;
    $dir = lc($dir);
    return 1 if ($dir eq '.svn');
    return 1 if ($dir eq 'cvs');
    return 0;
}

sub exclude_dir($) {
    my ($dir) = shift;
    foreach my $d (@excluded_dirs) {
        if ($dir =~ "/$d/") {
            return 1;
        }
    }
    return 0;
}

sub local_is_c_source {
    my ($f) = shift;
    if ( ($f =~ /\.c$/i) || ($f =~ /\.cpp$/i) || ($f =~ /\.cxx$/i) ||
         ($f =~ /\.inl$/i) || ($f =~ /\.cc$/i) ) {
        return 1;
    }
    return 0;
}

sub local_is_h_special {
    my ($f) = shift;
    if (($f =~ /osg/i)||($f =~ /OpenThreads/i)||($f =~ /Producer/i)) {
        return 1;
    }
    return 0;
}

sub local_is_h_source {
    my ($f) = shift;
    if ( ($f =~ /\.h$/i) || ($f =~ /\.hpp$/i) || ($f =~ /\.hxx$/i) ) {
        return 1;
    }
    return 0;
}

sub is_dsw_file {
    my ($f) = shift;
    if ( ($f =~ /\.dsw$/i) || ($f =~ /\.dsp$/i) ) {
        return 1;
    }
    return 0;
}

sub is_sln_file {
    my ($f) = shift;
    if ( ($f =~ /\.sln$/i) || ($f =~ /\.vcproj$/i) ) {
        return 1;
    }
    return 0;
}

sub is_ch_source {
    my ($f) = shift;
    if (is_c_source($f) || is_h_source($f)) {
        return 1;
    }
    return 0;
}

sub is_my_type {
    my ($f) = shift;
    if (is_c_source($f)) {
        $tot_c_sources++;
        return $TYPE_C;
    } elsif (is_h_source($f)) {
        $tot_h_sources++;
        return $TYPE_H;
    } elsif (is_dsw_file($f)) {
        $tot_dsw_sources++;
        return $TYPE_DSW;
    } elsif (is_sln_file($f)) {
        $tot_sln_sources++;
        return $TYPE_SLN;
    } elsif ($f =~ /^Makefile\.(am|in)$/i) {
        $tot_am_files++;
        return $TYPE_AM;
    } elsif ($f =~ /makefile/i) {
        $tot_mk_files++;
        return $TYPE_MAK;
    }
    $tot_others++;
    my ($nm, $dr, $fe) = fileparse( $f, qr/\.[^.]*/ );
    if (defined $missed_exts{$fe}) {
        $missed_exts{$fe}++;
    } else {
        $missed_exts{$fe} = 1;
    }
    return $TYPE_NONE;
}

sub get_top_files($$) {
    my ($td,$lev) = @_;
    my @dirs = ();
    my ($ff,$df,@dfiles,$typ,$nam,$dir,$rd);
    $td = unix_2_dos($td);    # ensure DOS form
    #$td .= "\\" if (substr($td,length($td)-1) ne "\\"); # add trailing, if none
    $td .= "\\" if !($td =~ /\\$/); # add trailing, if none
    prt("Moment, getting full file list of $td...\n" ) if ($lev == 0);
    if (opendir(DIR, $td)) {
        @dfiles = readdir(DIR);
        close DIR;
        foreach $df (@dfiles) {
            next if (($df eq '.') || ($df eq '..'));
            $ff = $td.$df;
            if (-f $ff) {
                $typ = is_my_type($df);
                ($nam,$dir) = fileparse($ff);
                #my $rd = get_relative_path( $dir, $td );
                $rd = get_relative_path_2( $dir, $td );
                ##my $rd = unix_2_dos($rp);
                #                 0    1    2  3     4
                push(@all_files, [$df, $ff, 0, $typ, $rd]) if ($typ);
            } elsif (-d $ff) {
                push(@dirs,$ff) if (!exclude_cvs_svn($df));
            } else {
                prtw( "WARNING: What is THIS [$ff] ???\n" );
            }
        }
    } else {
        prtw( "WARNING: Unable to OPEN directory $td ...\n" );
    }
    foreach $ff (@dirs) {
        get_top_files($ff,($lev + 1));
    }
    prt( "Got ".scalar @all_files." files ...\n" ) if ($lev == 0);
}

# fix relative directory - fix relative path - path fix
# Remove any DOT or DOUBLE DOT from the PATH
sub loc_fix_rel($) {
    my ($path) = shift;
    $path = unix_2_dos($path);    # ensure DOS separator
    my @a = split(/\\/, $path);    # split on DOS separator
    my $npath = '';
    my $wmsg = '';
    my $max = scalar @a;
    my @na = ();
    for (my $i = 0; $i < $max; $i++) {
        my $p = $a[$i];
        if ($p eq '.') {
            # ignore this
        } elsif ($p eq '..') {
            if (@na) {
                pop @na;    # discard previous
            } else {
                prtw( "WARNING: Got relative .. without previous!!! [$path]" );
            }
        } else {
            push(@na,$p);
        }
    }
    foreach my $pt (@na) {
        $npath .= "\\" if length($npath);
        $npath .= $pt;
    }
    return $npath;
}

sub is_c_source_ext($) {
    my ($ext) = shift;
    my $fe = lc($ext);
    if (($fe eq '.c')||($fe eq '.cxx')||($fe eq '.cpp')) {
        return 1;
    }
    return 0;
}

sub is_h_source_ext($) {
    my ($ext) = shift;
    my $fe = lc($ext);
    if (($fe eq '.h')||($fe eq '.hxx')||($fe eq '.hpp')) {
        return 1;
    }
    return 0;
}

sub is_am_source_ext($) {
    my ($ext) = shift;
    $ext = lc($ext);
    if ($ext eq '.am') {
        return 1;
    }
    return 0;
}

sub is_am_file($) {
    my ($fil) = shift;
    my ($fnm, $fdir, $fe) = fileparse( $fil, qr/\.[^.]*/ );
    return is_am_source_ext($fe);
}

sub process_one_file($) {
    my $afile = shift;
    my ($am_file,$mk);
    my ($fil_name, $fil_dir) = fileparse($afile);
    #$full_fil_path = unix_2_dos($main_root_dir . $fil_dir);
    $full_fil_path = loc_fix_rel($main_root_dir . $fil_dir);    # also returns DOS, minus trailing '\'
    $full_fil_path .= "\\" if ( !($full_fil_path =~ /\\$/) );        # add trailing '\' IF none
    # 2010-08-26 - This does NOT account for Makefile.in!!! Soooo
    #$next_am_file = $afile;
    #$next_am_file .= ".am" if (has_no_extent($afile) && !is_am_file($afile));
    $next_am_file = get_next_am_file($afile,"process_one_file");

    prt( "\n[dbg20] Processing [$next_am_file] from input_files array ...\n" ) if ($dbg20);
    process_am_file($dsp_package, $afile, $main_root_dir) if !exclude_dir($afile);
    $am_file = get_next_full_am_file($afile);
    $mk = mark_all_files($am_file);
    prtw( "WARNING:1: NOT FOUND IN MARK [$am_file]!\n" ) if (!$mk);
}


sub lib_in_projects($$) {
   my ($lib,$rp) = @_;
   foreach my $p (@{$rp}) {
          my ($dsp,$name) = split ',', $p;
      if ($lib eq $name) {
         return 1;
      }
   }
   return 0;
}

# 10/02/2010 Add dependencies
# Package=<4>
#{{{
#    Begin Project Dependency
#    Project_Dep_Name SimGear
#    End Project Dependency
#}}}

sub generate_dsw($$$) {
    my ($dsw_name, $rpacks, $rdeps) = @_;
    my ($proj,@arr,$lib,$deps,$lib2,$cnt);
    $cnt = scalar @{$rpacks};
    if ($cnt == 0) {
        prtd( "Avoided creating $dsw_name, since NO packages to add!\n" );
        return;
    }
    prtd( "Creating $dsw_name ...\nrenaming any original to OLD or BAK ...\n" );
    rename_2_old_bak( $dsw_name );
    open(DSW, ">$dsw_name") || mydie( "Can't create $dsw_name: $!\n" );

    print DSW <<EOF;
Microsoft Developer Studio Workspace File, Format Version 6.00
# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE!

EOF

    foreach my $p (@{$rpacks}) {
        print DSW "###############################################################################\n\n";
        my ($dsp,$name) = split ',', $p;
        print DSW "Project: \"$name\"=\"$dsp\" - Package Owner=<4>\n\n";
        print DSW <<EOF;
Package=<5>
{{{
}}}

EOF
      print DSW "Package=<4>\n";
      print DSW "{{{\n";
      foreach $proj (keys %{$rdeps}) {
         if ($proj eq $name) {
            $deps = ${$rdeps}{$proj};
            @arr = split(/\*/,$deps);
            if (@arr) {
               foreach $lib (@arr) {
                  $lib2 = "lib".$lib;
                  if (lib_in_projects($lib2,$rpacks)) {
                     print DSW "    Begin Project Dependency\n";
                     print DSW "    Project_Dep_Name $lib2\n";
                     print DSW "    End Project Dependency\n";
                  } else {
                     prtw("WARNING: [$lib2] NO FOUND in PROJECTS!\n");
                  }
               }
            }
            last;
         }

      }
      print DSW "}}}\n\n";
   }

   print DSW <<EOF;
###############################################################################

Global:

Package=<5>
{{{
}}}

Package=<3>
{{{
}}}

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

EOF

    close(DSW);
    prtd("Written $dsw_name...\n");
}

sub gen_temp_dsw($) {
    my ($rd) = shift;   # = $main_root_dir
    $rd =~ s/(\\|\/)$//; # s/\\$//;
    my ($out_file,$tmp_out,$dsp);
    $out_file = $target_dir;
    $out_file .= "\\" if !($out_file =~ /(\\|\/)$/);
    if (length($dsp_package)) {
        $out_file .= $dsp_package;
    } else {
        my ($f,$d) = fileparse($rd);
        $out_file .= $f;
    }
    $out_file .= '.dsw';
    $out_file = path_u2d($out_file);
    $dsp = $out_file;
    # ONLY generate a TEMP DSW in the $perl_dir
    ###########################################
    if ($write_temp_ds) {
        $tmp_out = $perl_dir;
        $tmp_out .= "\\" if (length($tmp_out) && !($tmp_out =~ /(\\|\/)$/) );
        if (length($dsp_package)) {
            $tmp_out .= 'temp.'.$dsp_package.'.dsw';
        } else {
            $tmp_out .= 'temp_list.dsw';
        }
        $tmp_out = path_u2d($tmp_out);
        push(@copy_bat,[$tmp_out,$out_file]);
        $out_file = $tmp_out;   # switch to using TEMP FILE

    }
    if ($only_dry_run) {
        prtw("WARNING: Would write [$tmp_out], for [$dsp], but DRY RUN is ON\n");
    } else {
        generate_dsw( $out_file, \@dspprojs, \%other_deps );
    }
}

# =====================================================
#######################################################################
##### all subs below

sub extract_am_projects {
    my ($file, @arr, $lib, $lsc);
    foreach $file (@msvc_c_files) {
        ##prt( "$file\n" );
        @arr = split(/\|/ , $file);    # get Lib | Source | Title
        if (scalar @arr == 3) {
            $lib = $arr[0];
            $lsc = $arr[1];
            if (defined $am_projects{$lib}) {
                $am_projects{$lib} .= '|'.$lsc;
            } else {
                $am_projects{$lib} = $lsc;
            }
        } else {
            prtw( "WARNING: Did NOT split as EXPECTED!!! [$file] ...\n\n" );
        }
    }

   # 2009-06-09 - also extract the HEADERS
    foreach $file (@msvc_h_files) {
        ##prt( "$file\n" );
        @arr = split(/\|/ , $file);    # get Lib | Source | Title
        if (scalar @arr == 3) {
            $lib = $arr[0];
            $lsc = $arr[1]; # but it appears these are NOT target relative! NEED FIX *TBD*
            if (defined $am_headers{$lib}) {
                $am_headers{$lib} .= '|'.$lsc;
            } else {
                $am_headers{$lib} = $lsc;
            }
        } else {
            prtw( "WARNING: Did NOT split as EXPECTED!!! [$file] ...\n\n" );
        }
    }
}


sub gen_inc_hash_others {
    my ($rd) = shift;
    my ($lsrcs, @arr, $sf, $s, $ind, $ff, $mk, $om);
    my ($in_file, $in_dir, $rel_src);
    my $out_file = '';
    my @incs = ();
    $last_dsp_file = '';
    foreach my $key (keys %other_projs) {
        $lsrcs = $other_projs{$key};  # extract LIST of SOURCES
        @arr = split(/\*/, $lsrcs);    # get sources
        foreach $sf (@arr) {
            $s = $sf;
            if (-f $sf) {
                $ff = $sf;
            } else {
                $ind = index($s, '$(top_srcdir)');
                $s = substr($s, $ind + 14) if ($ind >= 0);
                $s = loc_fix_rel($s);
                $ff = $rd . $s;
            }

            @incs = ();
            get_include_list("giho", $sf, $ff, \@incs);
            if (defined $inc_hash{$s}) {
                prtw( "WARNING:others:[dbg42] [$sf] [$s] ALREADY IN inc_hash!\n" ) if ($dbg42);
                $inc_hash{$s} .= join(' ', @incs);
            } else {
                $inc_hash{$s} = join(' ', @incs);
            }
        }
    }
}

sub gen_inc_hash_am {
   my ($rd) = shift;
    my ($sf, $s, $ff, $mk, $om);
   my ($lsrcs, @arr);
   my @incs = ();
    foreach my $key (keys %am_projects) {
        $lsrcs = $am_projects{$key};
        @arr = split(/\|/ , $lsrcs);    # Sources
        foreach $sf (@arr) {
            $s = loc_fix_rel($sf);
            $ff = $rd . $s;
            @incs = ();
            get_include_list("giha", $sf, $ff, \@incs);
            if (defined $inc_hash{$s}) {
                prtw( "WARNING:am: [$sf] [$s] ALREADY IN inc_hash!\n" ) if ($dbg42);
                $inc_hash{$s} .= join(' ',@incs);
            } else {
                $inc_hash{$s} = join(' ',@incs);
            }
        }
    }
}

sub show_other_projects {
    my ($rd) = shift;
    my ($lsrcs, @arr, $s, $sf, $ind, $ff, $mk, $om);
    my ($in_file, $in_dir, $rel_src);
    my ($out_file,$tmp_out);
    $last_dsp_file = '';
    prt( "\nFound $o_cnt OTHER projects ...root = $rd\n" );
    foreach my $key (keys %other_projs) {
        $lsrcs = $other_projs{$key};
        $out_file = $target_dir;
        $out_file .= "\\" if !($out_file =~ /(\\|\/)$/);
        $out_file .= $key.'.dsp';
        $out_file = path_u2d($out_file);
        # ONLY GENERATE TEMPORARY DSP FILE in the $perl_dir
        if ($write_temp_ds) {
            $tmp_out = $perl_dir;
            $tmp_out .= "\\" if !($tmp_out =~ /(\\|\/)$/);
            $tmp_out .= 'temp.'.$key.'.dsp';
            $tmp_out = path_u2d($tmp_out);
            push(@copy_bat,[$tmp_out,$out_file]);
            $out_file = $tmp_out;
        }
        push(@dspprojs, ".\\$key.dsp,$key");
        @arr = split(/\*/, $lsrcs);    # get sources SPLIT
        prt( "Project: $key\n" );
        foreach $sf (@arr) {
            $s = $sf;
            $ind = index($s, '$(top_srcdir)');
            $s = substr($s, $ind + 14) if ($ind >= 0);
            $s = loc_fix_rel($s);
            $ff = $rd . $s;
            $mk = mark_all_files($ff);
            ($in_file, $in_dir) = fileparse($ff);
            #                             source, target
            #$rel_src = get_relative_path( $in_dir, $outdir );
            #$rel_src = get_relative_path_2( $in_dir, $outdir );
            $rel_src = get_relative_path_2( $in_dir, $target_dir );
            # pgm_exit(1,"Key $key: Source file [$sf] [$s] dir=[$in_dir] targ=[$target_dir] rel=[$rel_src] file[$in_file]\n");
            $rel_src .= $in_file;

            $rel_src = unix_2_dos($rel_src);
            if (is_c_source($s)) {
                if ($check4main2) {
                    $om = get_main_msg($ff,$s,0,$rel_src); # check if a main()
                } else {
                    $om = "File:C:  [$s] ff=[$ff] ";
                    $om .= "(rs=$rel_src)" if ($add_rel_src);
                }
                $om .= "C SOURCE NOT FOUND IN MARK!" if (!$mk);
                prt("$om\n");
                # generate DSP file
                out_dsp_file($key, $out_file, $rel_src, $rd, 0) if ($out_dsp2);
            } else {
                $om = "File:H:  [$s] ";
                $om .= "(rs=$rel_src)" if ($add_rel_src);
                $om .= "NOT FOUND IN MARK!" if (!$mk);
                prt("$om\n");
            }
        }
    }
    if ( length($last_dsp_file)) {
        # this is also where HEADERS are added
        end_dsp_file($last_dsp_file) if ($out_dsp2);
        $last_dsp_file = '';
    }
}

# need 'root' to do DSP/DSW
sub show_am_projects {
    my ($rd) = shift;
    prt( "\nFound $p_cnt LIBRARY projects ...root = $rd\n" );
    my ($out_file,$tmp_out);
    my ($in_file, $in_dir, $rel_src);
    my ($s, $ff, $mk, $om);
    my ($lsrcs, @arr);
    foreach my $key (keys %am_projects) {
        $lsrcs = $am_projects{$key};
        $out_file = $target_dir;
        $out_file .= "\\" if !($out_file =~ /(\\|\/)$/);
        $out_file .= $key.'.dsp';
        $out_file = path_u2d($out_file);
        # ONLY GENERATE A TEMPORARY DSP FILE in the $perl_dir
        #$out_file = $outdir.$key.'.dsp';
        #$out_file = 'temp.'.$key.'.dsp';
        if ($write_temp_ds) {
            $tmp_out = $perl_dir;
            $tmp_out .= "\\" if !($tmp_out =~ /(\\|\/)$/);
            $tmp_out .= 'temp.'.$key.'.dsp';
            $tmp_out = path_u2d($tmp_out);
            push(@copy_bat,[$tmp_out,$out_file]);
            $out_file = $tmp_out;
        }
        # and store the relative actual DSP file name, for DSW generation
        push(@dspprojs, ".\\$key.dsp,$key");
        @arr = split(/\|/ , $lsrcs);    # Sources
        prt( "Project: $key\n" );
        foreach $s (@arr) {
            $s = loc_fix_rel($s);
            $ff = $rd . $s;
            ($in_file, $in_dir) = fileparse($ff);
            #                             source, target
            #$rel_src = get_relative_path( $in_dir, $outdir );
            #$rel_src = get_relative_path_2( $in_dir, $outdir );
            $rel_src = get_relative_path_2( $in_dir, $target_dir );
            $rel_src .= $in_file;
            $rel_src = unix_2_dos($rel_src);
            $mk = mark_all_files($ff);
            if ($check4main2) {
                $om = get_main_msg($ff,$s,0,$rel_src); # check if a main()
            } else {
                $om =  "File: [$s] ff=[$ff] ";
                $om .= "(rs=$rel_src)" if ($add_rel_src);
            }
            if (!$mk) {
                $om .= " NOT FOUND in MARK!";
            }
            prt("$om\n");
            # generate TEMP DSP file
            out_dsp_file($key, $out_file, $rel_src, $rd, 1) if ($out_dsp);
        }
    }

    if ( length($last_dsp_file) ) {
        # this is also where HEADERS, if any, are ADDED to the DSP
        end_dsp_file($last_dsp_file) if ($out_dsp);
        $last_dsp_file = '';
        $last_project = '';
    }
}

sub get_main_msg {
    my ($ffn,$sfn,$no,$rs) = @_;
    my $fom = "file:C: [$sfn] ff=[$ffn] ";
    $fom .=  "(rs=$rs)" if ($add_rel_src);
    my @cm = ();
    if (chk_main($ffn,\@cm)) {
        while (length($fom) < $min_line) {
            $fom .= ' ';
        }
        $fom .= " HAS main()";
        my $cmc = scalar @cm;
        for (my $t = 0; $t < $cmc; $t++) {
            $fom .= "\n  ".$cm[$t][0].": ".$cm[$t][1] if ($show_main);
            if (length($cm[$t][2])) {
                if ($show_cond) {
                    $fom .= " cond ".$cm[$t][2];
                } else {
                    $fom .= " cond";
                    last;
                }
            }
        }
    } elsif ($no) {
        while (length($fom) < $min_line) {
            $fom .= ' ';
        }
        $fom .= " NO main() FOUND";
    }
    return $fom;
}

sub test_root_folder($) {
    my $rd = shift;
    $rd .= "\\" if !($rd =~ /(\\|\/)$/);
    my $ff = path_u2d($rd.'configure.ac');
    return 1 if (-f $ff);
    $ff = path_u2d($rd.'configure.in');
    return 1 if (-f $ff);
    return 0;
}

sub scan_root_folder {
   my ($rd) = shift;
   $rd .= "\\" if !(substr($rd,-1,1) =~ /(\\|\/)/);
   my $ff = $rd;    
   $ff .= 'configure.ac';
   if (! -f $ff) {
       # try the ONLY altenative
       $ff = $rd.'configure.in';
       if (! -f $ff) {
           pgm_exit(1,"ERROR: Can NOT locate configure.ac nor configure.in in [$rd]! Aborting!\n");
       }
   }
   prt( "Scanning CONFIG file [$ff]...\n" );
   scan_one_configure_file($ff,$rd);
   $ff = $rd.'aclocal.m4';
   scan_one_configure_file($ff,$rd) if -f $ff;
   if (!@input_files) {
      prt( "Copying " . scalar @make_input_list . " make_input_list to input_files.\n" );
      @input_files = @make_input_list;
      %output_files = %make_list;
   } else {
      prt( "input_files has list of " . scalar @input_files . " ...\n" );
   }
    if ($dbg06) {
        my $cnt = scalar @input_files;
        prt( "\nOutput of $cnt input_files list ...\n" );
        $cnt = 0;
        foreach $ff (@input_files) {
            $cnt++;
            prt( "$cnt $ff\n" );
        }
        prt( "Done $cnt input_files list ...\n" );
    }
    pgm_exit(1,"ERROR: No 'makefiles' found in root folder scan!\n") if (!@input_files);
}

sub is_in_ac_done {
    my ($fil) = shift;
    foreach my $sd (@ac_scanned) {
        if( uc($fil) eq uc($sd) ) {
            return 1;
        }
    }
    return 0;
}

## my %config_ac_macros = ();
sub do_macro_sub2 {
    my ($item) = shift;
    prt( "[dbg27] Checking substitution for [$item] ...\n" ) if ($dbg27);
    if (defined $config_ac_macros{$item}) {    # if it is IN the MACROS
        my $ritem = $config_ac_macros{$item};    # extract the substitute value
        prt( "[dbg27] Found:do_macro_sub2: returning [$ritem] ...\n" ) if ($dbg27);
        return $ritem;
    } else {
        $undefined_macs{$item} = 1;
        prt( "[dbg27] NOT FOUND:do_macro_sub2: [$item] Added to undefined...\n" ) if ($dbg27);
    }
    return $item;
}


sub do_macro_sub {
    my ($item) = shift;
    if ($item =~ /^\$/) {
        my $msub = substr($item,1);    # remove leading '$'
        $msub =~ s/^\{(.+)\}$/$1/;
        my $ritem = do_macro_sub2($msub);
        if ($ritem ne $msub) {
            return $ritem;
        }
    }
    return $item;
}

sub drop_trailing_dots($) {
    my $fil = shift;
    $fil = path_u2d($fil);
    my @arr = split(/\\/,$fil);
    my ($path);
    my $nfil = '';
    foreach $path (@arr) {
        $path =~ s/\.$//;
        $nfil .= "\\" if (length($nfil));
        $nfil .= $path;
    }
    return $nfil;
}

sub is_shell_action($) {
    my $txt = shift;
    return 1 if ($txt =~ /^`.+`$/);
    return 0;
}

# 2010-08-27: This could be split(/\s/,$line), but there is a
# problem with name="with space", that this overcomes.
# Slower. but sure the split is as desired.
# This version obeys either type of quote - single or double
sub local_space_split($) {
	my ($lin) = shift;
	my $ll = length($lin);
	my $tag = '';
	my @rarr = ();
	my $inquots = 0;
    my ($p,$ch,$cq);
	for ($p = 0; $p < $ll; $p++) {
		$ch = substr($lin,$p,1);
		if ($inquots) {
			$tag .= $ch;
			if ($ch eq $cq) {
				$inquots = 0;
			}
		} else {
			if ($ch =~ /\s/) {
				push(@rarr, $tag) if (length($tag));
				$tag = '';
			} else {
				$tag .= $ch;
				if (($ch eq '"')||($ch eq "'")) {
					$inquots = 1;
                    $cq = $ch
				}
			}
		}
	}
	push(@rarr, $tag) if (length($tag));
	return @rarr;
}

sub local_strip_both_quotes($) {
    my $txt = shift;
    if ($txt =~ /^'(.+)'$/) {
        return $1;
    }
    if ($txt =~ /^"(.+)"$/) {
        return $1;
    }
    return $txt;
}

sub grep_for_value($$) {
    my ($file,$find) = @_;
    my $res = '';
    if (open INF,"<$file") {
        my @lns = <INF>;
        close INF;
        my ($ln,$ind);
        foreach $ln (@lns) {
            $ind = index($ln,$find);
            if ($ind >= 0) {
                chomp $ln;
                $res = $ln;
                last;
            }
        }
    } else {
        prtw("WARNING: Unable to open file [$file]\n");
    }
    return $res;
}

# cut range
# N   N'th byte, char or field, counted from 1
# N-  from N'th to end
# N-M from N'th to M'th (included)
# -M  from 1st to M'th (included)
sub get_cut_range($$) {
    my ($txt,$rrng) = @_;
    if ($txt =~ /^\d+$/) {
        # only digits
        if ($txt >= 1) {
            ${$rrng}[0] = 1;
            ${$rrng}[1] = $txt;
            return 1;
        }
    } elsif ($txt =~ /^\d+-\d*$/) {
        my @arr = split('-',$txt);
        my ($bgn,$end,$len);
        $len = scalar @arr;
        if ($len == 1) {
            $bgn = $arr[0];
            if ($bgn >= 1) {
                ${$rrng}[0] = $bgn;
                ${$rrng}[1] = -1;
                return 1;
            }
        } elsif ($len == 2) {
            $bgn = $arr[0];
            $end = $arr[1];
            if (($bgn >= 1)&&($end >= $bgn)) {
                ${$rrng}[0] = $bgn;
                ${$rrng}[1] = $end;
            }
        }
    } elsif ($txt =~ /^-/) {
        $txt = substr($txt,1);
        if ($txt =~ /^\d+$/) {
            ${$rrng}[0] = 1;
            ${$rrng}[1] = $txt;
            return 1;
        }
    }
    return 0;
}


sub set_by_shell_action($$$) {
    my ($dir,$key,$rval) = @_;
    my $val = ${$rval};
    my (@arr,$len,$act,$k,$res,$find,$file,$rng,$oval,$rlen);
    $res = '';
    $oval = $val;
    prt("Set by shell [$key] val [${$rval}], in dir [$dir]\n") if ($dbg37);
    if ($val =~ /^`(.+)`$/) {
        $val = $1;
        @arr = local_space_split($val);
        $len = scalar @arr;
        for ($k = 0; $k < $len; $k++) {
            $act = $arr[$k];
            if ($act eq 'grep') {
               # ok expect 'something' in file
               if (($k + 2) < $len) {
                   $k++;
                   $find = strip_both_quotes($arr[$k]);
                   $k++;
                   $file = $arr[$k];
                   $file =~ s/\$\{srcdir\}/$dir/;
                   $file = path_u2d($file);
                   $file =~ s/\\\\/\\/g;
                   prt("Act = $act, find [$find], in [$file]\n") if ($dbg37);
                   $res = grep_for_value($file,$find);
                   if (length($res)) {
                       prt("Result: [$res]\n") if ($dbg37);
                   } else {
                       prtw("WARNING: grep_for_value: $act, find [$find], in [$file] in [$dir] FAILED!\n");
                   }
               }
            } elsif ($act eq 'cut') {
                # expect - like cut -c 29-
                $k++;
                if ($k < $len) {
                    $find = $arr[$k];
                    $k++;
                    if ($k < $len) {
                        $file = $arr[$k];
                        prt("Act = $act, type [$find], range [$file]\n") if ($dbg37);
                        $rlen = length($res);
                        if ($rlen) {
                            my (@rng); # cut range
                            if (get_cut_range($file,\@rng)) {
                                my ($bgn,$end,$dif);
                                $bgn = $rng[0];
                                $end = $rng[1];
                                prt("Got 'cut' range [$bgn] to [".(($end == -1) ? "End" : $end)."], on string [$rlen]\n") if ($dbg37);
                                if ($end == -1) {
                                    if (($bgn - 1) < $rlen) {
                                        $val = substr($res,($bgn - 1));
                                    } else {
                                        $val = '';
                                    }
                                } else {
                                    $dif = $end - $bgn + 1;
                                    $bgn--;
                                    $val = substr($res,$bgn,$dif);
                                }
                            }
                        }
                    }
                }
            } elsif ($act eq '|') {
                prt("Act = $act\n") if ($dbg37);
            }
        }
    }
    if ($dbg37) {
        prt("Setting NEW value [$val]\n") if ($val ne $oval);
    }
    ${$rval} = $val;
}

sub get_sub_for($$) {
    my ($item,$rval) = @_;
    my ($nval);
    if (defined $config_ac_macros{$item}) {
        $nval = $config_ac_macros{$item};
        if ( !($nval =~ /\$/) ) {
            ${$rval} = $nval;
            return 1;
        }
    }
    if (defined $IN_MACS{$item}) {
        $nval = $IN_MACS{$item};
        if ( !($nval =~ /\$/) ) {
            ${$rval} = $nval;
            return 1;
        }
    }
    return 0;
}

# deal with messy things like
sub do_mac_subs($$$$);
# key [CXX_FOR_BUILD] val [${CXX_FOR_BUILD:-'$(CXX)'}]
# key [MATCH_LIMIT_RECURSION] val [-DMATCH_LIMIT_RECURSION=$withval]
# key [BUILD_EXEEXT] val [${BUILD_EXEEXT:-'$(EXEEXT)'}]
# key [CFLAGS_FOR_BUILD] val [${CFLAGS_FOR_BUILD:-'$(CFLAGS)'}]
# key [PCRE_VERSION] val [${PCRE_MAJOR}.${PCRE_MINOR}${PCRE_PRERELEASE}]
# key [PCRE_MAJOR] val [`grep '#define PCRE_MAJOR' ${srcdir}/pcre.h | cut -c 29-`]
sub do_mac_subs($$$$) {
    my ($dir,$key,$val,$lev) = @_;
    #prt("Mac Subs key [$key] val [$val], in dir [$dir]\n");
    my ($sub,$nval,$mac);
    if (is_shell_action($val)) {
        set_by_shell_action($dir,$key,\$val);
    } elsif ($val =~ /\$/) {
        # probably some substitution required!
        $sub = $key.":-";
        if ($val =~ /$sub/) {
            $val =~ s/$sub//;
        }
        # ${'$(CXXFLAGS)'}
        if ($val =~ /^\$\{'\$\((\w+)\)'\}$/) {
            $sub = $1;
            if (get_sub_for($sub,\$nval)) {
                $val = $nval;
                return $val;
            }
        }
        if ($val =~ /^\$\{(\w+):-(.+)\}$/) {
            $sub = "\${".$1;
            $mac = strip_both_quotes($2);
            $val =~ s/$sub//;
            $val =~ s/\}$//;
            if ($mac =~ /^\$\{'\$\((\w+)\)'\}$/) {
                $sub = $1;
                if (get_sub_for($sub,\$nval)) {
                    $val = $nval;
                    return $val;
                }
            }
        }
        # [${PCRE_MAJOR}.${PCRE_MINOR}${PCRE_PRERELEASE}
        while ($val =~ /\$\{(\w+)\}/) {
            $sub = $1;
            if (get_sub_for($sub,\$nval)) {
                prt(" [dbg38] Got SUB for [$val] item '\${$sub}' TO [$nval]\n") if ($dbg38);
                $val =~ s/\$\{$sub\}/$nval/;
                prt(" [dbg38] Value after the SUB [$val]\n") if ($dbg38);
            } else {
                prt(" [dbg38] FAILED to get SUB for [$val] [$sub]\n") if ($dbg38);
                last;
            }
        }
    }
    return $val;
}

# separate ${JACK_API_CURRENT}:${JACK_API_REVISION}:${JACK_API_AGE}
# [dbg01] 109: [JACK_VERSION=$JACK_MAJOR_VERSION.$JACK_MINOR_VERSION.${JACK_MICRO_VERSION}${BETA}]
sub macro_split($) {
    my ($txt) = @_;
    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));
                    $tag = '';
                    push(@arr,$mac);
                    $ch = '';
                    $i = $k;
                }
            } elsif (($k+2) < $len) {
                $mac = '$'; # without {...}
                for (; $k < $len; $k++) {
                    $nc = substr($txt,$k,1);
                    last if !($nc =~ /\w/); # until NOT \w char, or string ended
                    $mac .= $nc;    # accumulate the macro
                }
                push(@arr,$tag) if (length($tag));
                $tag = '';
                push(@arr,$mac);
                $ch = '';
                $i = $k;
            }
        }
        $tag .= $ch;
    }
    return @arr;
}

# like [dbg01] JACK_SO_VERSION=${JACK_API_CURRENT}:${JACK_API_REVISION}:${JACK_API_AGE}
sub try_for_substitution($$$$) {
    my ($val,$lnn,$rh,$by) = @_;
    if ($val =~ /\$\{\w+\}/) {
        prt("[dbg48] $lnn: try_for_substitution: for [$val] in $by\n") if ($dbg48);
        my $oval = $val;
        my @arr = macro_split($val);
        my ($item,$key,$nval,$cnt);
        $cnt = 0;
        foreach $item (@arr) {
            $cnt++;
            next if ($item =~ /^\s+$/);
            prt("[dbg48] $lnn:$cnt: Checking [$item]\n") if ($dbg48);
            if ($item =~ /^\$\{(\w+)\}$/) {
                $key = $1;
                if (defined ${$rh}{$key}) {
                    $nval = ${$rh}{$key};
                    if ($nval =~ /\$/) {
                        prt("[dbg48] $lnn:$cnt: [$key] Can NOT replace a macro with another [$nval]\n") if ($dbg48);
                        $incompete_macs{$key} = $by;
                    } else {
                        #$mac = '\\${'.$key.'}';
                        $val =~ s/\$\{$key\}/$nval/;
                        prt("[dbg48] $lnn:$cnt: [$key] Doing sustitution [$key] TO [$nval]\n") if ($dbg48);
                    }
                } else {
                    $undefined_macs{$key} = $by;
                    prt("[dbg48] $lnn:$cnt: Added key [$key] to undefined macros...\n") if ($dbg48);
                    #$mac = '\\${'.$key.'}';
                    $val =~ s/\$\{$key\}//;
                    prt("[dbg48] $lnn:$cnt: [$key] Doing sustitution [$key] TO [<blank>]\n") if ($dbg48);
                }
            } elsif ($item =~ /^\$(\w+)$/) {
                $key = $1;
                if (defined ${$rh}{$key}) {
                    $nval = ${$rh}{$key};
                    if ($nval =~ /\$/) {
                        prt("[dbg48] $lnn:$cnt: [$key] Can NOT replace a macro with another [$nval]\n") if ($dbg48);
                        $incompete_macs{$key} = $by;
                    } else {
                        #$mac = '\\$'.$key;
                        $val =~ s/\$$key/$nval/;
                        prt("[dbg48] $lnn:$cnt: [$key] Doing sustitution [$key] TO [$nval]\n") if ($dbg48);
                    }
                } else {
                    $undefined_macs{$key} = $by;
                    prt("[dbg48] $lnn:$cnt: Added key [$key] to undefined macros...\n") if ($dbg48);
                    #$mac = '\\$'.$key;
                    $val =~ s/\$$key//;
                    prt("[dbg48] $lnn:$cnt: [$key] Doing sustitution [$key] TO [<blank>]\n") if ($dbg48);
                }
            } else {
                prt("[dbg48] $lnn:$cnt: No match of [$item]\n") if ($dbg48);
            }
        }
        if ($val ne $oval) {
            prt("[dbg48] $lnn:$cnt: Changed to [$val]\n") if ($dbg48);
        }
    }
    return $val;
}

sub eat_ac_macro($$$$) {
    my ($line,$max,$ri,$rlines) = @_;
    my $len = length($line);
    my ($i,$ch,$brcnt,$k,$k2,$lcnt,$acmac);
    # 1 - Eat the AC MACRO NAME
    $acmac = '';
    $k = ${$ri};
    for ($i = 0; $i < $len; $i++) {
        $ch = substr($line,$i,1);
        last if (!($ch =~ /\w/));
        $acmac .= $ch;
    }
    if ($ch ne '(') {
        pgm_exit(1,"ERROR: mac=[$acmac] Fix eat_ac_macro to accept [$ch] following 'name'!\n");
    }
    $i++;
    # essentially get to END of MACRO - may be mutiple lines
    $brcnt = 0;
    $lcnt = 1;
    for (; $i < $len; $i++) {
        $ch = substr($line,$i,1);
        if ($ch eq '(') {
            $brcnt++;
        } elsif ($ch eq ')') {
            if ($brcnt) {
                $brcnt--;
            } else {
                last;
            }
        }
    }
    if ($ch ne ')') {   # oops, need more lines
        $k++;
        $k2 = $k + 1;
        # prt( "[dbg01] $k2: need more lines...($brcnt)\n" ) if ($dbg01);
        while ($k < $max) {
            $line = trim_all(${$rlines}[$k]);
            $lcnt++;
            $len = length($line);
            prt( "[dbg01] $k2: [$line] AC_MACRO cont...($brcnt) line $lcnt, len $len\n" ) if ($dbg01);
            for ($i = 0; $i < $len; $i++) {
                $ch = substr($line,$i,1);
                if ($ch eq '(') {
                    #prt("Bumped brcnt [$brcnt]\n");
                    $brcnt++;
                } elsif ($ch eq ')') {
                    if ($brcnt) {
                        $brcnt--;
                        $ch = '';   # CLEAR this char - is NOT the end
                        #prt("Decrement brcnt [$brcnt]\n");
                    } else {
                        #prt( "[dbg01] $k2: Multipline macro EXIT1...($brcnt) lines $lcnt\n" ) if ($dbg01);
                        last;
                    }
                }
            }
            if ($ch eq ')') {
                prt( "[dbg01] $k2: Multipline [$acmac] macro EXIT2... lines $lcnt\n\n" ) if ($dbg01);
                last;
            }
            $k++;   # need MORE
            $k2 = $k + 1;
        }
        pgm_exit(1,"ERROR: Ran out of line in an ac macro!\n") if ($k >= $max);
        ${$ri} = $k;    # pass back line number
    }
}


sub scan_one_configure_file {
    my ($filename, $rd) = @_;
    # $filename = path_u2d($filename);
    $filename = drop_trailing_dots($filename);
    if( is_in_ac_done($filename) ) {
        prtw("[dbg34] WARNING: Avoided repeated scan of [$filename]!\n") if ($dbg34);
        return;
    }
    if (! -f $filename) {
       pgm_exit(1,"ERROR: Can NOT find file [$filename]!\n" );
    }

    if (! open CONFIGURE, "<$filename") {
       #prtw( "WARNING: can't open '$filename': $!\n" );
       pgm_exit(1,"ERROR: can't open [$filename] Reason: $!\n" );
       return;
    }
    my @lines = <CONFIGURE>;
    close CONFIGURE;

    push(@ac_scanned, $filename);
    prt("Processing configure file [$filename]...\n");
    my ($ac_name,$ac_dir) = fileparse($filename);
    my $in_ac_output = 0;
    my $ac_output_line = '';
    my ($ff,$fline,$cline,$acline);
    my $aclnum = 0;
    my %var_hash = ();
    my ($key,$nval);
    my ($local,$input,@rest);
    my ($one_hdr,$item,@arr);
    my $lncnt = scalar @lines;
    my ($i);
    for ($i = 0; $i < $lncnt; $i++) {
        $aclnum = $i + 1;
        $fline = $lines[$i];
        $cline = $fline;    # copy current file line
        chomp $cline;
        $acline = trim_all($cline);
        ###prt( "$cline\n" );
        # Remove comments from current line.
        next if ($acline =~ /^dnl\s+/);
        next if ($acline =~ /^#/);
        next if (length($acline) == 0);
        prt( "[dbg01] $aclnum: [$cline]\n" ) if ($dbg01);
        if (($acline =~ /^(\w+)\(/) && (defined $ac_macro_skip{$1})) {
            eat_ac_macro($acline,$lncnt,\$i,\@lines);
            next;
        }

        #if ($cline =~ /^\s*(\w+)="(\d+)"$/) {
        if ($cline =~ /^\s*(\w+)="*(\d+)"*$/) {
            $key = $1;
            $nval = strip_both_quotes($2);
            prt("[dbg03|32] MACRO:N: [$key]=[$nval] line:$aclnum: [$acline]\n" ) if ($dbg32 || $dbg03);
            $var_hash{$key} = $nval;
            $config_ac_macros{$key} = $nval;
        ##} elsif ($cline =~ /^(\w+)="(.+)"$/) {
        ##} elsif ($cline =~ /^(\w+)="{0,1}(.+)"{0,1}$/) {
        ##} elsif ($cline =~ /^(\w+)=(.+)$/) {
        } elsif ($cline =~ /^\s*(\w+)=(.+)$/) {
            $key  = $1;
            $nval = strip_both_quotes($2);
            #prt( "[dbg03] Sub [$key]=[$nval]\n" ) if ($dbg03);
            $nval = try_for_substitution($nval,$aclnum,\%config_ac_macros,"config_ac_macros");
            prt("[dbg03|32] MACRO:S: [$key]=[$nval] line:$aclnum: [$acline]\n" ) if ($dbg32 || $dbg03);
            $var_hash{$key} = $nval;
            $config_ac_macros{$key} = $nval;
        } elsif ($cline =~ /^\s*(\w+)=\s*$/) {
            $key = $1;
            $nval = '';
            prt("[dbg03|32] MACRO:B: [$key]=[$nval] line:$aclnum: [$acline]\n" ) if ($dbg32 || $dbg03);
            $var_hash{$key} = $nval;
            $config_ac_macros{$key} = $nval;
        } elsif ($cline =~ /=/) {
            if (is_if_else_endif($cline)) {
                # this CAN have a equal sign
            } else {
                prtw( "WARNING: '=' NOT handled! line:$aclnum: [$acline]\n" );
            }
        }

        # Skip macro definitions.  Otherwise we might be confused into
        # thinking that a macro that was only defined was actually
        # used.

        # Follow includes.  This is a weirdness commonly in use at
        # Cygnus and hopefully nowhere else.
        if (($cline =~ /sinclude\((.*)\)/) && (-f ($rd.$1))) {
            $ff = $rd.$1;
            scan_one_configure_file ($ff, $rd);
        }

        if (!$in_ac_output && (($cline =~ s/AC_OUTPUT\s*\(\[?//) || ($cline =~ s/AC_CONFIG_FILES\s*\(\[?// ) ) ) {
            $in_ac_output = 1;
            $ac_output_line = $aclnum;    # get LINE number
            prt( "[dbg4] Got ac_output_line = [$ac_output_line] ...\n" ) if ($dbg04);
        }

        if ($in_ac_output) {
            my $closing = 0;
            if ($cline =~ s/[\]\),].*$//) {
                $in_ac_output = 0;
                $closing = 1;
            }

            # Look at potential Makefile.am's
            @arr = split(/\s/,$cline);
            foreach $item (@arr) {
                # Must skip empty string for Perl 4.
                next if (($item eq "\\") || ($item eq ''));

                ($local,$input,@rest) = split(/:/,$item);
                if (!$input) {
                    $input = $local;
                } else {
                    $input =~ s/\.in$//;
                }
                $ff = $rd . $input . '.am';
                if (-f $ff) {
                    prt( "[dbg05] Adding $input [$ff] to make_input_list ...\n" ) if ($dbg05);
                    push(@make_input_list, $input);
                    $make_list{$input} = join(':', ($local,@rest));
                } else {
                    # try HARDER with 'Makefile'
                    if ($input =~ /^Makefile$/) {
                        $ff = $rd . $input . '.in';
                        if (-f $ff) {
                            prt( "[dbg05] Adding $input [$ff] to make_input_list ...\n" ) if ($dbg05);
                            push(@make_input_list, $input);
                            $make_list{$input} = join(':', ($local,@rest));
                            next;
                        }
                    }
                    prt( "[dbg05] Adding $input [$ff] to other_input_files ...\n" ) if ($dbg05);
                    # We have a file that automake should cause to be
                    # rebuilt, but shouldn't generate itself.
                    push (@other_input_files, $item);
                }
            }
        }

        # Handle configuration headers.  A config header of `[$1]'
        # means we are actually scanning AM_CONFIG_HEADER from
        # aclocal.m4.
        if (($cline =~ /A([CM])_CONFIG_HEADER\s*\((.*)\)/) && ($2 ne '[$1]')) {
            if (($1 eq 'C') && $abort_on_ac_config) {
                am_conf_line_error($filename, $aclnum,
                    "automake requires AM_CONFIG_HEADER, not AC_CONFIG_HEADER");
            }
            $config_header_line = $aclnum;
            foreach $one_hdr (split (' ', $2)) {
                push (@config_fullnames, $one_hdr);
                if ($one_hdr =~ /^([^:]+):(.+)$/) {
                    push (@config_names, $1);
                    push (@config_headers, $2);
                } else {
                    push (@config_names, $one_hdr);
                    push (@config_headers, $one_hdr . '.in');
                }
            }
        }

        if ($cline =~ /$AM_CONDITIONAL_PATTERN/o) {
            prt( "[dbg31] $aclnum: [$acline]\n" ) if ($dbg31);
            if ( defined $cfg_defines{$1} ) {
                # has been DEFINED in am2dsp?.cfg file, or previously defined
                prt( "[dbg02] Storing configure_cond key $1 ... value=2\n" ) if ($dbg02);
                $configure_cond{$1} = 2;
            } else {
                prt( "[dbg02] Storing configure_cond key $1 ... value=1\n" ) if ($dbg02);
                $configure_cond{$1} = 1;
            }
        }

        if ($cline =~ /$AM_INIT_AUTOMAKE/o) {
            $dsp_package = $1;
            $dsp_version = $2;
            prt( "Got AM_INIT_AUTOMAKE($dsp_package, $dsp_version) ...\n" );

            $dsp_package = do_macro_sub($dsp_package);
            $dsp_version = do_macro_sub($dsp_version);
            prt( "Set DSP package = $dsp_package, DSP version = $dsp_version ...\n" );
        }
    }

    prt("Done scan of [$filename]... processed $aclnum lines...\n");
    prt("Package = [$dsp_package], version = [$dsp_version]\n");
    prt("Full Names: [".join(", ",@config_fullnames)."]\n");
    prt("Names: [".join(", ",@config_names)."]\n");
    prt("Headers: [".join(", ",@config_headers)."]\n");
    prt("Got ".scalar @make_input_list." make input items...\n");
    #  $make_list{$input} = join(':', ($local,@rest));
    if ($dbg47) {
        foreach $input (@make_input_list) {
            $nval = $make_list{$input};
            prt(" $input = [$nval]\n");
        }
    }
    # $config_ac_macros{$key} = $nval;
    prt("Got ".scalar keys(%config_ac_macros)." items in \%config_ac_macros...\n");
    $acline = 0;
    while ($acline < 2) {
        $acline++;
        prt("\n[dbg38] Run $acline...\n") if ($dbg38);
        foreach $key (keys %config_ac_macros) {
            $one_hdr = $config_ac_macros{$key};
            $nval = do_mac_subs($ac_dir,$key,$one_hdr,$acline);
            if (defined $IN_MACS{$key}) {
                $cline = $IN_MACS{$key};
                if ($nval eq $cline) {
                    prt(" [dbg38] $key = [$nval], no change\n") if ($dbg38);
                } else {
                    prt(" [dbg38] $key = [$nval], changed from [$cline]\n") if ($dbg38);
                    $IN_MACS{$key} = $nval;
                }
            } else {
                $IN_MACS{$key} = $nval;
                prt(" [dbg38] $key = [$nval], NEW\n") if ($dbg38);
            }
            if ("$one_hdr" ne "$nval") {
                $config_ac_macros{$key} = $nval;
            }
        }
    }
    if (length($temp_in_macs)) {
        # = $perl_dir."\\tempinmac.txt";
        $one_hdr = '';
        $acline = 0;
        foreach $key (sort keys %IN_MACS) {
            $nval = $IN_MACS{$key};
            $one_hdr .= " '$key' => ";
            if ($nval =~ /^\d+$/) {
                $one_hdr .= "$nval,\n";
            } else {
                $one_hdr .= "'$nval',\n";
            }
            $acline++;
        }
        write2file($one_hdr,$temp_in_macs);
        prtw("WARNING:debug: Written $acline IN_MACS to [$temp_in_macs]...\n");
    }
    ##### pgm_exit(1,"TEMPORARY CHECK");
}


sub am_error {
    my ($msg) = shift;
    pgm_exit($exit_status,"ERROR: $msg\n");
}

sub am_conf_line_error {
    my (@args) = @_;
    am_error("am_conf_line_error: ".join(' ',@args));
}

sub am_line_error {
    my ($symbol, @args) = @_;
    prt( "am_line_error: sym=[$symbol] arg0=[$args[0]] ...\n" );
    if ($symbol && "$symbol" ne '-1') {
        my ($file) = "$active_am_file";
        if ($symbol =~ /^\d+$/) {
            # SYMBOL is a line number, so just add the colon.
            $file .= ':' . $symbol;
        } elsif (defined $content_lines{$symbol}) {
            # SYMBOL is a variable defined in Makefile.am, so add the
            # line number we saved from there.
            $file .= ':' . $content_lines{$symbol};
        } elsif (defined $configure_vars{$symbol}) {
            # SYMBOL is a variable defined in configure.ac, so add the
            # appropriate line number.
            $file = $configure_vars{$symbol};
        } else {
            # Couldn't find the line number.
        }
        ###warn $file, ": ", join (' ', @args), "\n";
        prt( "$file: ". join (' ', @args). "\n" );
        $exit_status = 1;
      prt( "ERROR EXIT!\n" );
        close_log($outfile,1);
        exit($exit_status);
    } else {
        am_error (join(' ',@args));
    }
}


sub initialize_per_input {
    # These two variables are used when generating each Makefile.in.
    # They hold the Makefile.in until it is ready to be printed.
    $output_vars = '';
    $output_trailer = '';

    # This holds the contents of a Makefile.am, as parsed by
    # read_am_file.
    %contents = ();

    # This holds the names which are targets.  These also appear in
    # %contents.
    %targets = ();

    # For a variable or target which is defined conditionally, this
    # holds an array of the conditional values.  The array is composed
    # of pairs of condition strings (the variables which configure
    # will substitute) and values (the value of a target is
    # meaningless).  For an unconditional variable, this is empty.
    %conditional = ();

    # This holds the line numbers at which various elements of
    # %contents are defined.
    %content_lines = ();

    # This holds a 1 if a particular variable was examined.
    %content_seen = ();

    # This is the conditional stack.
    @conditional_stack = ();

    # This holds the set of included files.
    @include_stack = ();

    # This holds the "relative directory" of the current Makefile.in.
    # Eg for src/Makefile.in, this is "src".
    $relative_dir = '';

    # This maps the source extension of a suffix rule to its
    # corresponding output extension.
    %suffix_rules = ();

    # per AM file sources
    @am_c_files = ();
    @am_h_files = ();
    @am_o_files = ();
}

sub unique_proj {
    my ($prj) = shift;
    if (defined $other_projs{$prj}) {
        my $nprj = $prj;
        my $i = 0;
        while (defined $other_projs{$nprj}) {
            $i++;
            $nprj = "$prj$i";
        }
        return $nprj;
    }
    return $prj;
}

sub get_lib_depends($) {
    my ($deps) = shift;  # = ($contents{$ky});
    # like bvhtest_LDADD = libsgbvh.a -lsgstructure -lsgmath $(base_LIBS)
    # [openal_test1]=[$(top_builddir)/simgear/debug/libsgdebug.a $(openal_LIBS)]
    my @arr = split(' ',$deps);
    my $srcs = '';
    my ($f,$fi,$fil,$dir);
    foreach $f (@arr) {
        $fi = $f;
        $fi = substr($fi,16) if ($fi =~ /^\$\(top_builddir\)\//);   # remove top_builddir...
        next if ($fi =~ /^\$\(\w+\)$/);  # for the moment IGNORE '$(base_LIBS)', '$(openal_LIBS)'...
        ($fil,$dir) = fileparse($fi);    # only want filename at end
        if ($fil =~ /^lib(\w+)\.a$/) {
            $fil = $1;  # chop off 'lib(.+).a'
        } elsif ($fil =~ /^-l/) {
            $fil = substr($fil,2); # remove '-l' at front
        } else {
            prtw("WARNING:get_lib_depends: CHECKOUT this item [$fi] [$fil]! deps=[$deps]\n");
            $fil = '';
        }
        if (length($fil)) {
            next if ($fil eq 'z');        # forget libz
            next if ($fil eq 'stdc++');   # and stdc
            $srcs .= "*" if (length($srcs)); # add separator
            $srcs .= $fil; # and this item
        }
    }
    return $srcs;  # return LIST
}

# process for OTHER THAN LIBRARIES
sub process_other_sources {
    my ($mf, $rd) = @_;
    my ($nam, $dir, $ext) = fileparse( $mf, qr/\.[^.]*/ );
    my $rel_dir = dirname($mf);
    # like 'noinst_PROGRAMS = calc_loc'
    # and then 'calc_loc_SOURCES = calc_loc.cxx'
    my ($key, $projs, $proj, $proj2, $ky, $fnd, $skey, $fil, $srcs, $fi, $dnmf, $dndir, $uproj);
    my ($typ, $proj3);
    my $bas_dir = ".\\";
    my @dir_cont = ();
    my @proj_arr = ();
    my @proj_files = ();
    $fnd = 0;
    $dnmf = 0;
   foreach $key (keys %contents) {
        $projs = $contents{$key};    # get PROJECT name
        #if (($key eq 'noinst_PROGRAMS')||($key eq 'bin_PROGRAMS')) {
        if ( $key =~ /(.+)_PROGRAMS/) {
         $typ = $1;  # usually 'noinst' or 'bin', but ...
            @proj_arr = split(' ', $projs);    # split in case multiple
            foreach $proj (@proj_arr) {    # process each project, getting the SOURCES
                $proj2 = $proj;
                $proj2 =~ s/-/_/g;  # change hyphen (-) to underscore (_)
                foreach $ky (keys %contents) {
                    if (($ky =~ /($proj)_SOURCES/) || ($ky =~ /($proj2)_SOURCES/)){
                        $skey = $ky;
                        $fnd = 1;
                        last;
                    }
                }
                if ($fnd) {
                    @proj_files = split(' ', $contents{$skey});
                    #prt( "Project: [$proj] - sources [".$contents{$skey}."]\n" );
                    $srcs = '';
                    # generate LIST of SOURCES
                    foreach $fil (@proj_files) {
                        if ($fil =~ /^\$\(([^\)]*)\)$/) {
                            # Found a variable.
                            my $varname = $1;
                            if (defined $contents{$varname}) {
                                my @f2 = split(' ', $contents{$varname});
                                foreach $fi (@f2) {
                                    $srcs .= '*' if (length($srcs));
                                    $srcs .= unix_2_dos($bas_dir . $rel_dir . "\\" . $fi);
                                }
                            } else {
                                $srcs .= '*' if (length($srcs));
                                $srcs .= unix_2_dos($bas_dir . $rel_dir . "\\" . $fil);
                            }
                        } else {
                            $srcs .= '*' if (length($srcs));
                            $srcs .= unix_2_dos($bas_dir . $rel_dir . "\\" . $fil);
                        }
                    }
                    $uproj = unique_proj($proj);
                    prt( "[dbg21] Project:O:1: [$proj] - sources [$srcs] [$uproj]\n" ) if ($dbg21);
                    $other_projs{$uproj} = $srcs;    # keep this PROJECT, and SOURCES (both c and h) LIST of SOURCE
                    find_am_includes( $proj, $uproj, $rd );
                    foreach $ky (keys %contents) {
                        if (($ky =~ /($proj)_LDADD/) || ($ky =~ /($proj2)_LDADD/)){
                            $srcs = get_lib_depends($contents{$ky});
                            if (length($srcs)) {
                                $other_deps{$uproj} = $srcs;
                                prt("[dbg29] Found dependencies [$uproj]=[$srcs].\n") if ($dbg29);
                            }
                            last;
                        }
                    }
                } else {
                    prtw("WARNING:[dbg45] Using a LOOSE search, since [$proj] nor [$proj2]_SOURCES NOT FOUNT!\n") if ($dbg45);
                    # so, just search for SOURCES - may be a MACRO, which did not expand!!!
                    foreach $ky (keys %contents) {
                        if ($ky =~ /(.+)_SOURCES/) {
                            $proj3 = $1;    # maybe this is the PROJECT name
                            $skey = $ky;
                            $fnd = 1;
                            last;
                        }
                    }
                    if ($fnd) {
                        @proj_files = split(' ', $contents{$skey});
                        #prt( "Project: [$proj] - sources [".$contents{$skey}."]\n" );
                        $srcs = '';
                        foreach $fil (@proj_files) {
                            if ($fil =~ /^\$\(([^\)]*)\)$/) {
                                # Found a variable.
                                my $varname = $1;
                                if (defined $contents{$varname}) {
                                    my @f2 = split(' ', $contents{$varname});
                                    foreach $fi (@f2) {
                                        $srcs .= '*' if (length($srcs));
                                        $srcs .= unix_2_dos($bas_dir . $rel_dir . "\\" . $fi);
                                    }
                                } else {
                                    $srcs .= '*' if (length($srcs));
                                    $srcs .= unix_2_dos($bas_dir . $rel_dir . "\\" . $fil);
                                }
                            } else {
                                $srcs .= '*' if (length($srcs));
                                $srcs .= unix_2_dos($bas_dir . $rel_dir . "\\" . $fil);
                            }
                        }
                        $uproj = unique_proj($proj3);
                        prt( "[dbg21] Project:O:2: [$proj] - sources [$srcs] [$uproj]\n" ) if ($dbg21);
                        $other_projs{$uproj} = $srcs;    # keep this PROJECT, and SOURCES (both c and h)
                        find_am_includes( $proj3, $uproj, $rd );
                    } else {
                        # if we can FIND a C source in the folder OF THE SAME NAME
                        # as this project
                        if ( !$dndir ) {
                            prtw("WARNING: Even LOOSE search FAILED for [$proj] and [$proj2] READING DIRECTORY!\n");
                            $fil = $rd . $rel_dir;
                            if (opendir( DIR, $fil)) {
                                @dir_cont = readdir(DIR);
                                close DIR;
                                prt( "[dbg23] Found ".scalar @dir_cont." items in [$fil]\n" ) if ($dbg23);
                            } else {
                                prtw( "WARNING: FAILED to OPEN DIRECTORY [$fil] ...\n" );
                            }
                            $dndir = 1;
                        }
                        $srcs = '';
                        $fnd = 0;
                        if ( @dir_cont ) {
                            # check contents of local directory
                            foreach $fi (@dir_cont) {
                                next if (($fi eq '.')||($fi eq '..'));
                                $fil = $rd . $rel_dir . "\\" . $fi;
                                if ( is_c_source($fi) && (-f $fil)) {
                                    if ($fi =~ /$proj\..+/) {
                                        $srcs = unix_2_dos($rel_dir . "\\" . $fi);
                                        $fnd = 1;
                                        last;
                                    }
                                }
                            }
                        }
                        if ($fnd) {
                            $uproj = unique_proj($proj);
                            prt( "[dbg21|23] Project:O:3: [$proj] - sources [$srcs] [$uproj]\n" ) if ($dbg21 || $dbg23);
                            $other_projs{$uproj} = $srcs;    # keep this PROJECT
                            $fnd = 0;
                            find_am_includes( $proj, $uproj, $rd );
                        } else {
                            prt( "Processing file [$mf] ...\n" ) if (!$dnmf);
                            if ($proj =~ /^\@.+\@$/) {
                                $proj = substr($proj,1,length($proj)-2);
                                my $msub = do_macro_sub2($proj);
                                prtw( "WARNING: Project: @[$proj]@ = [$msub] - NO SOURCES FOUND???\n" );
                            } else {
                                prtw( "WARNING: Project: [$proj] - NO SOURCES FOUND???\n" );
                            }
                            $dnmf = 1;
                        }
                    }
                }
            } # for each $proj in @proj_arr - that is EACH PROGRAM
        }  # if ( $key =~ /(.+)_PROGRAMS/)
    }  # for each key in the Makefile.am file - key = something
}

sub replace_top_srcdir {
    my ($nam,$rd) = @_;
    if ($nam =~ /\$\(([^\)]*)\)/ ) {
        my $mac = $1;
        prt( "[dbg25] Checking [$mac] ...\n" ) if ($dbg25);
        if (($mac eq 'top_srcdir')  ||
            ($mac eq 'top_builddir') ) {
            $nam =~ s/\$\(${mac}\)/$rd/;
            $nam = unix_2_dos($nam);
            $nam =~ s/\\{2}/\\/g;
            prt( "[dbg25] Substituted [$nam] ...\n" ) if ($dbg25);
        }
    }
    return $nam;
}

sub find_am_includes {
    my ( $proj, $group, $rd ) = @_;
    ### FIND INCLUDES
    #################
    # like INCLUDES = -I$(top_srcdir)/include
    my $incs = '';
    my @files = ();
    my $cnt = 0;
    my $nam = '';
    my $mac = '';
    my $ii = 0;
    my $jj = 0;
    my $k2 = '';
    foreach $k2 (keys %contents) {
        if ($k2 eq 'INCLUDES') {
            $incs = $contents{$k2};
            last;
        }
    }
    $incs = trim_all($incs);
    if (length($incs)) {
        prt( "Got INCLUDES [$incs] ...\n" ) if ($dbg25);
        @files = split(' ',$incs);
        $cnt = scalar @files;
        for ($ii = 0; $ii < $cnt; $ii++) {
            $nam = $files[$ii];
            $nam =~ s/^-I//;
            $nam = replace_top_srcdir($nam,$rd);
            $files[$ii] = $nam;
        }
        # remove any DUPLICATES
        for ($ii = 0; $ii < $cnt; $ii++) {
            $nam = $files[$ii];
            if (length($nam)) {
                for ($jj = 0; $jj < $cnt; $jj++) {
                    if ($ii != $jj) {
                        if ($nam eq $files[$jj]) {
                            $files[$jj] = '';
                        }
                    }
                }
            }
        }
        $incs = join(' ', @files);
    }
    $am_includes{$group} = $incs;
    prt( "[dbg26] For $group, saved INCLUDES [$incs]\n" ) if ($dbg26);

    # STATICCPPFLAGS = -DCURL_STATICLIB
    # CPPFLAGS = -DCURL_NO_OLDIES $(STATICCPPFLAGS)
    $incs = '';
    foreach $k2 (keys %contents) {
        if ($k2 eq 'CPPFLAGS') {
            $incs = $contents{$k2};
            last;
        }
    }
    $incs = trim_all($incs);
    if (length($incs)) {
        prt( "Got CPPFLAGS [$incs] ...\n" ) if ($dbg25);
        @files = split(' ',$incs);
        $cnt = scalar @files;
        for ($ii = 0; $ii < $cnt; $ii++) {
            $nam = $files[$ii];
            $nam =~ s/^-D//;
            if ($nam =~ /\$\(([^\)]*)\)/ ) {
                $mac = $1;
                prt( "Checking [$mac] ...\n" ) if ($dbg25);
                if (defined $contents{$mac}) {
                    my $mac2 = $contents{$mac};
                    $nam =~ s/\$\(${mac}\)/$mac2/;
                    $nam =~ s/^-D//;
                    prt( "Substituted [$nam] ...\n" ) if ($dbg25);
                }
            }
            $files[$ii] = $nam;
        }
        $incs = join(' ', @files);
    }
    prt( "[dbg26] For $group, saved CPPFLAGS [$incs]\n" ) if ($dbg26);
    $am_cppflags{$group} = $incs;
    # LIBDIR = $(top_builddir)/lib
    # LDADD = $(LIBDIR)/libcurl.la
    $incs = '';
    foreach $k2 (keys %contents) {
        #if ($k2 eq 'LDADD') {
        if ($k2 =~ /LDADD/) {
            $incs = $contents{$k2};
            last;
        }
    }
    $incs = trim_all($incs);
    if (length($incs)) {
        prt( "Got LDADD [$incs] ...\n" ) if ($dbg25);
        @files = split(' ',$incs);
        $cnt = scalar @files;
        for ($ii = 0; $ii < $cnt; $ii++) {
            $nam = $files[$ii];
            $nam =~ s/^-I//;
            if ($nam =~ /\$\(([^\)]*)\)/ ) {
                $mac = $1;
                prt( "Checking [$mac] ...\n" ) if ($dbg25);
                if (defined $contents{$mac}) {
                    my $mac2 = $contents{$mac};
                    $mac2 = replace_top_srcdir($mac2,$rd);
                    $nam =~ s/\$\(${mac}\)/$mac2/;
                    $nam = unix_2_dos($nam);
                    if ($nam =~ /lib(\w+)\.la/) {
                        $nam =~ s/lib(\w+)\.la/Lib_${1}\.lib/;
                    }
                    prt( "Substituted [$nam] ...\n" ) if ($dbg25);
                }
            }
            $files[$ii] = $nam;
        }
        $incs = join(' ', @files);
    }
    prt( "[dbg26] For $group, saved LDADD [$incs]\n" ) if ($dbg26);
    $am_libadds{$group} = $incs;

}

sub strip_single_quotes {
	my ($ln) = shift;
	if ($ln =~ /^'.*'$/) {
		$ln = substr($ln,1,length($ln)-2);
	}
	return $ln;
}

sub massage_key($$) {
    my ($k,$rd) = @_;
    $k = strip_quotes($k);
    $k = strip_single_quotes($k);
    $k = trim_all($k);
    if ($k =~ /^\$\((.+)\)/) {
        my $m = $1;
        if (($m eq 'top_srcdir')  ||
            ($m eq 'top_builddir') ) {
            $k = replace_top_srcdir($k,$rd);
        } elsif ($k =~ /^\$\((.+)\)$/) {
            $k = $m;
        }
    }
    return $k;
}

sub is_skipped_item($) {
    my $t = shift;
    return 1 if ($t =~ /^-/);
    return 1 if ($t eq 'mv');
    return 1 if ($t eq '<');
    return 1 if ($t eq '>');
    return 1 if ($t eq '&&');
    return 1 if ($t =~ /^#/);
    return 1 if ($t =~ /^s#/);
    return 0;
}

sub add_2_new_source_list($$$$) {
    my ($line,$rsa,$rdh,$grp) = @_;
    my $ok = 0;
    my $odir = $target_dir;
    my ($cfil,$cdir) = fileparse($line);
    my $rdir = get_rel_dos_path($cdir,$odir);
    my $sfil = $rdir.$cfil;
    return if (defined ${$rdh}{$sfil});
    ${$rdh}{$sfil} = 1;
    my ($filter,$group);
    prt("[dbg41] add_2_new_source_list: [$line] grp=[$grp], rel=[$sfil]\n") if ($dbg41);
    if (is_c_source_extended($line)) {
        # if (($line =~ /\.cxx$/i) || ($line =~ /\.c$/i) || ($line =~ /\.cpp$/i) || ($line =~ /\.cc$/i))
        $filter = get_def_src_filt();
        $group = get_def_src_grp();
        $ok = 1;
    } elsif (is_h_source_extended($line)) {
        # elsif ( ($line =~ /\.hxx$/i) || ($line =~ /\.h$/i) || ($line =~ /\.hpp$/i) )
        $filter = get_def_hdr_filt();
        $group = get_def_hdr_grp();
        $ok = 2;
    } elsif (is_resource_file($line)) {
        $filter = get_def_rcs_filt();
        $group = get_def_rcs_grp();
        $ok = 3;
    }

    if ($ok) {
        #               0,     1       2        3  4=full file name
        #push(@sources, [ $line, $group, $filter, 0, '' ]);
        push(@{$rsa}, [ $sfil, $group, $filter, 0, $line ]);
        if (($ok == 1)||($ok == 2)) {
            add_2_source_list(subract_source_dir($line),$grp);
        }
    } else {
        if (! defined $discarded{$line}) {
            prtw("WARNING: CHECK Discarded [$line]\n");
            $discarded{$line} = 1;
        }
	}
    #if (@sources) {
    #    $key = 'PROJECT_SRCS';
    #    ${$hr}{$key} = [@sources];
    return $ok;
}

sub get_proj_name($) {
    my ($key) = shift;
    return $key if ($key =~ /^\w+$/);
    my ($n,$d,$e) = fileparse( $key, qr/\.[^.]*/ );
    if ($d =~ /\.(\\|\/)$/) {
        if ($e eq '.la') {
            return $n;
        }
    }
    return 'testproj';
}

sub process_in_file_contents($$$) {
    my ($dsp_file,$file_in,$rd) = @_;
    # search for target 'all' or 'default'
    my $all = '';
    prt("Processing the contents of [$file_in]...\n");
    my ($key,$val,@arr,$key2,$val2,@arr2,$key3,$val3,@arr3,$key4,$val4,@arr4);
    my ($mac,$ok,$key5,$val5,@arr5,$project,$targ);
    my %keyh = ();
    my %dupes = ();
    my %projs = ();
    my @sources = ();
    my $rkeys = \%keyh;
    $project = '';
    $targ = '';
    $act_rel_directory = $rd;
    foreach $key (keys %contents) {
        if ($key eq 'all') {
            $all .= ' ' if (length($all));
            $all .= $contents{$key};
            $targ .= ':' if (length($targ));
            $targ .= 'all';
        } elsif ($key eq 'default') {
            $all .= ' ' if (length($all));
            $all .= $contents{$key};
            $targ .= ':' if (length($targ));
            $targ .= 'default';
        }
    }
    if (length($all)) {
        prt("Examine targets:$targ: [$all]\n");
        @arr = split(/\s/,$all);
        foreach $key (@arr) {
            $key = massage_key($key,$rd);
            next if (length($key) == 0);
            next if (is_skipped_item($key));
            $project = get_proj_name($key);
            %{$rkeys} = ();
            ${$rkeys}{$key} = 1;
            if (defined $contents{$key}) {
                $val = trim_all($contents{$key});
                prt("\ntarg:[$key] = [$val]\n") if ($dbg39);
                @arr2 = split(/\s/,$val);
                foreach $key2 (@arr2) {
                    $key2 = massage_key($key2,$rd);
                    next if (length($key2) == 0);
                    next if (is_skipped_item($key2));
                    next if (defined ${$rkeys}{$key2});    # do NOT expand twice
                    ${$rkeys}{$key2} = 1;
                    if (defined $contents{$key2}) {
                        $val2 = trim_all($contents{$key2});
                        next if (length($val2) == 0);
                        prt(" rule:1:[$key2] = [$val2]\n") if ($dbg39);
                        @arr3 = split(/\s/,$val2);
                        foreach $key3 (@arr3) {
                            $key3 = massage_key($key3,$rd);
                            next if (length($key3) == 0);
                            next if (is_skipped_item($key3));
                            next if (defined ${$rkeys}{$key3});    # do NOT expand twice
                            ${$rkeys}{$key3} = 1;
                            if (defined $contents{$key3}) {
                                $val3 = trim_all($contents{$key3});
                                next if (length($val3) == 0);
                                prt("  rule:2:[$key3] = [$val3]\n") if ($dbg39);
                                #----------
                                @arr4 = split(/\s/,$val3);
                                foreach $key4 (@arr4) {
                                    $key4 = massage_key($key4,$rd);
                                    next if (length($key4) == 0);
                                    next if (is_skipped_item($key4));
                                    next if (defined ${$rkeys}{$key4});    # do NOT expand twice
                                    ${$rkeys}{$key4} = 1;
                                    if (defined $contents{$key4}) {
                                        $val4 = trim_all($contents{$key4});
                                        next if (length($val4) == 0);
                                        prt("   rule:3:[$key4] = [$val4]\n") if ($dbg39);
                                        #----------
                                        @arr5 = split(/\s/,$val4);
                                        foreach $key5 (@arr5) {
                                            $key5 = massage_key($key5,$rd);
                                            next if (length($key5) == 0);
                                            next if (is_skipped_item($key5));
                                            next if (defined ${$rkeys}{$key5});    # do NOT expand twice
                                            ${$rkeys}{$key5} = 1;
                                            if (defined $contents{$key5}) {
                                                $val5 = trim_all($contents{$key5});
                                                next if (length($val5) == 0);
                                                prt("    rule:4:[$key5] = [$val5]\n") if ($dbg39);
                                            } else {
                                                $ok = "NOT DEFINED";
                                                if (-f $key5) {
                                                    add_2_new_source_list($key5,\@sources,\%dupes,$project);
                                                    $ok = "FILE";
                                                }
                                                prt("    rule:4:[$key5] = $ok\n") if ($dbg39);
                                            }
                                        }
                                        #----------
                                    } else {
                                        $ok = "NOT DEFINED";
                                        if (-f $key4) {
                                            add_2_new_source_list($key4,\@sources,\%dupes,$project);
                                            $ok = "FILE";
                                        }
                                        prt("   rule:3:[$key4] = $ok\n") if ($dbg39);
                                    }
                                }
                                #----------
                            } else {
                                $ok = "NOT DEFINED";
                                if (-f $key3) {
                                    add_2_new_source_list($key2,\@sources,\%dupes,$project);
                                    $ok = "FILE";
                                }
                                prt("  rule:2:[$key3] = $ok\n") if ($dbg39);
                            }
                        }
                    } else {
                        $ok = "NOT DEFINED";
                        if (-f $key2) {
                            add_2_new_source_list($key2,\@sources,\%dupes,$project);
                            $ok = "FILE";
                        }
                        prt(" rule:1:[$key2] = $ok\n") if ($dbg39);
                    }
                }
            } else {
                $ok = "NOT DEFINED";
                if (-f $key) {
                    add_2_new_source_list($key,\@sources,\%dupes,$project);
                    $ok = "FILE";
                }
                prt("targ:[$key] = $ok\n") if ($dbg39);
            }
            if (@sources) {
                if (defined $projs{$project}) {
                    $val = $projs{$project};
                    push(@{$val},@sources);
                } else {
                    $projs{$project} = [@sources];
                }
            }
            @sources = ();
            %dupes = ();
        }
    } else {
        prtw("WARNING: No target 'all', or 'default' found in [$file_in]\n");
    }
    $val = scalar keys %projs;
    if ($val) {
        prt("Found $val projects in [$file_in]...\n");
        if ($dbg40) {
            my ($k,$ra,$min,$len);
    #    foreach $file (@msvc_c_files) {
    #        ##prt( "$file\n" );
    #        @arr = split(/\|/ , $file);    # get Lib | Source | Title
            foreach $key (keys %projs) {
                $ra = $projs{$key};
                $val = scalar @{$ra};
                $min = 0;
                for ($k = 0; $k < $val; $k++) {
                    #push(@{$rsa}, [ $sfil, $group, $filter, 0, '' ]);
                    $val2 = ${$ra}[$k][0];
                    $len = length($val2);
                    $min = $len if ($len > $min);
                }
            }
            foreach $key (keys %projs) {
                $ra = $projs{$key};
                $val = scalar @{$ra};
                prt("Project $key has $val sources...\n");
                for ($k = 0; $k < $val; $k++) {
                    #push(@{$rsa}, [ $sfil, $group, $filter, 0, '' ]);
                    $val2 = ${$ra}[$k][0];
                    $val3 = ${$ra}[$k][1];
                    $val2 .= ' ' while (length($val2) < $min);
                    prt("$val2 group:[$val3]\n");
                }
            }
        }
    } else {
        prtw("WARNING: No PROJECTS found in [$file_in]\n");
    }

    ##### pgm_exit(1,"TEMP EXIT TO REVIEW KEY EXPANSION");
}

sub process_am_file {
    my ($dsp_name,$makefile,$rd) = @_;
    my $base_dir = './';
    my $dsp_file = $rd . $dsp_name . '.dsp';
    ###my $relative_dir = dirname($makefile);
    $relative_dir = dirname($makefile);
    my $dupe = 0;
    my @files = ();
    my $key = '';
    my $group = 'Lib_Special';
    my $file = '';    # full path to file
    my $fi = '';    # filename only
    my $ext = '';    # and its extension
    my $dir = '';    # directory it is in
    my $nam = '';    # file title
    my $proj = '';
    my $cnt = 0;
    my $fnd = 0;
    my $gotsubd = 0;
    my $gotinch = 0;
    # build AM file name
    my $file_am = $rd . $makefile;
    # 04/04/2008 READ 'configure.ac' if present in THIS DIRECTORY
    # ===========================================================
    my $file_ac = $full_fil_path . "configure.ac";
    if ( -f $file_ac ) {
        # if we have an configure.ac file here
        scan_one_configure_file( $file_ac, $rd );
    }
    #$file_am .= '.am' if !($file_am =~ /\.am$/i);
    $file_am = get_next_full_am_file($makefile);
    $current_am_file = sub_common_folder($file_am,$rd);

    prt( "[dbg24] Processing AM file [$current_am_file]\n" ) if ($dbg24);

    push(@done_am,$file_am);

    initialize_per_input();     # clear out previous

    read_main_am_file($file_am, $rd);

    # preview the 'contents' to find 'group'
    $cnt = scalar keys(%contents);
    prt( "\n[dbg19|28]:CT: Got $cnt items in \%contents from file $file_am...\n" ) if ($dbg28 || $dbg19);
    $cnt = 0;
    my $lib_cnt = 0;
    my $prog_cnt = 0;
    my $lib_scnt = 0;
    my $prog_cnt2 = 0;
    my $src_cnt2 = 0;
    my $lt_libs = 0;

    # missing like a2j_client_LTLIBRARIES
    foreach $key (keys %contents) {
        $file = trim_all($contents{$key});
        @files = split(' ',$file);
        $fnd = scalar @files;
        $cnt++;
        # NOTE this pattern
        # [dbg19|28]:CT:4: [plugin_LTLIBRARIES] = [jack_sun.la]
        # [dbg19|28]:CT:5: [jack_sun_la_LDFLAGS] = [-module -avoid-version]
        # [dbg19|28]:CT:7: [jack_sun_la_SOURCES] = [sun_driver.c sun_driver.h]
        # so we have a plugin_LTLIBRARIES, so the project name is jack_sun[.la]
        # and then we have the SOURCES... !!!
        prt( "[dbg19|28]:CT:$cnt: [$key] = [$file]\n" )if ($dbg28 || $dbg19);
        if ($key =~ /\s*([\w-]+)_LIBRARIES\s*/) {
            $lib_cnt++;
        } elsif ($key =~ /\s*([\w-]+)_LTLIBRARIES\s*/) {
            $lt_libs++;
        } elsif ($key =~ /\s*([\w-]+)_PROGRAMS\s*/) {
            $prog_cnt++;
        } elsif (($key =~ /lib(.*)_a_SOURCES/)  ||
           ($key =~ /lib(.*)_la_SOURCES/) ||
           ($key =~ /libc(.*)_la_SOURCES/) ) {
            $lib_scnt += $fnd;
        } elsif ( $key =~ /(.+)_PROGRAMS/) {
            #if (($key eq 'noinst_PROGRAMS')||($key eq 'bin_PROGRAMS')) {
            $prog_cnt2 += $fnd;
        } elsif ($key =~ /(.+)_SOURCES/) {
            $src_cnt2 += $fnd;
        } elsif ($key =~ /SUBDIRS/) { # DIST_SUBDIRS
            $gotsubd += $fnd;
        } elsif ($key =~ /HEADERS/) { # include_HEADERS, noinst_HEADERS
            $gotinch += $fnd;
        }
    }
    if ($dbg28 || $dbg19) {
        if ($lib_cnt || $lib_scnt || $prog_cnt || $src_cnt2 || $lt_libs) {
            prt( "[dbg19|28]:CT: Done $cnt libs=$lib_cnt, lt_libs=$lt_libs, lib_src=$lib_scnt, prog=$prog_cnt, src=$src_cnt2...\n" );
        } else {
            prt( "[dbg19|28]:CT: Done $cnt No library, programs or sources\n" );
        }
    }
    if ($act_am_ext =~ /^\.in$/) {
        process_in_file_contents($dsp_file,$file_am,$rd);
        $content_by_file{$file_am} = { %contents };
        return;
    }

    if ($lib_cnt && $prog_cnt) {
        prtw("WARNING: Present script LOGIC may be FLAWED\n");
    }

    ###############################################################
    ## process various contents of %contents
    ##############################################################
    # 2010-08-29 - This logic is FLAWED - Could be MULTIPLE LIBS and PROGRAMS per Makefile.am
    # use 'noinst_LIBRARIES' macro
    foreach $key (keys %contents) {
        #if ($key eq 'noinst_LIBRARIES') {
        if ($key =~ /\s*([\w-]+)_LIBRARIES\s*/) {
            @files = split(' ', $contents{$key});
            foreach $file (@files) {
                if ($file =~ /^lib([\w-]+)\.a/) {
                    $group = 'lib' . $1;
                    prt( "Group set to [$group] ... file $file_am ...\n" ) if ($dbg08 || $dbg33);
                    $fnd = 1;
                    last;
                }
            }
        }
    }
    if (!$fnd) {
      # found NOT LIBRARY item
      # try for check_PROGRAMS or bin_PROGRAMS
      foreach $key (keys %contents) {
         if ($key =~ /\s*([\w-]+)_PROGRAMS\s*/) {
            $nam = $1;
            @files = split(' ', $contents{$key});
            foreach $file (@files) {
               if ($file =~ /^([\w-]+)$/) {
                  ###$group = $nam.'_'. $1;
                  $group = $1;
                  prt( "Group set to [$group] ... file $file_am ...\n" ) if ($dbg08 || $dbg33);
                  $fnd = 1;
                  last;
               }
            }
         }
      }
    }
    # 10/02/2010 - NO warning IF it has a 'SUBDIRS' entry
    if (!$fnd && ($gotsubd == 0) && ($gotinch == 0)) {
       prtw( "WARNING: NO 'GROUP' FOUND in $file_am ...\n" );
    }

    # now extract LIBRARY SOURCES from 'contents' hash
    foreach $key (sort keys %contents) {
       #if ($key eq "include_HEADERS") {
       #} # not found in Makefile.am files?
       #if ($key =~ /^lib(.*)_a_SOURCES/) {
       #if (($key =~ /^lib(.*)_a_SOURCES/)  ||
         #    ($key =~ /^lib(.*)_la_SOURCES/) ||
         #    ($key =~ /^libc(.*)_la_SOURCES/) ) {
       if (($key =~ /lib(.*)_a_SOURCES/)  ||
           ($key =~ /lib(.*)_la_SOURCES/) ||
           ($key =~ /libc(.*)_la_SOURCES/) ) {
          $proj = $1;        # keep Project RAW name
          $group = 'lib' . $proj;    # generate a GROUP
          prt( "[08] Found SOURCES entry for LIBRARY [$key] [$proj]\n" ) if ($dbg08);
          @files = split(' ', $contents{$key});
          foreach (@files) {
             my $src_dir = $base_dir . $relative_dir . '/';
             $src_dir =~ s/\//\\/g; # fixup DOS path separators
             if (/^\$\(([^\)]*)\)$/) {
                # Found a variable.
                my $varname = $1;
                prt( "[08] Expanding variable $varname ...\n" ) if ($dbg08);
                foreach (split(' ', $contents{$varname})) {
                   $file = $src_dir . $_;
                   $dupe = add_2_source_list( $file, $group );
                }
                prt( "[08] Done expanding variable $varname ...\n" ) if ($dbg08);
             } else {
                $file = $src_dir . $_;
                $dupe = add_2_source_list( $file, $group );
             }
          }
          find_am_includes( $proj, $group, $rd );
       } elsif ($key eq "fgfs_SOURCES") {
          #elsif ($key =~ /(.*)_SOURCES/) {
          $group = 'main';
          @files = split(' ', $contents{$key});
          foreach $fi (@files) {
             my $sdir = $base_dir . $relative_dir . '/';
             $sdir =~ s/\//\\/g; # fixup DOS path separators
             $file = $sdir . $fi;
             $dupe = add_2_source_list( $file, $group );
          }
       } else {
          # key is NOT ( Lib(.*)_a_SOURCES fgfs_SOURCES )
          if (($key eq 'EXTRA_DIST')||($key eq 'fgjs_SOURCES')) {
             @files = split(' ', $contents{$key});
             foreach $fi (@files) {
                ($nam, $dir, $ext) = fileparse( $fi, qr/\.[^.]*/ );
                $file = $base_dir . $relative_dir . '/' . $fi;
                $file =~ s/\//\\/g; # use DOS path sep
                if (is_c_source_ext($ext)) {
                   push(@msvc_c_extra, $file);
                   prt( "Added [$file] to C EXTRA list\n" ) if $dbg09;
                } elsif (is_h_source_ext($ext)) {
                   push(@msvc_h_extra, $file);
                   prt( "Added [$file] to H EXTRA list\n" ) if $dbg09;
                } else {
                   push(@msvc_o_extra, $file);
                   prt( "Added [$file] to other EXTRA list\n" ) if $dbg09;
                }
             }
          } elsif ($key eq 'noinst_HEADERS') {
             # JSBSim has put the HEADERS in HERE,
             # FIX20061107
             # more recently SimGear put some 'source' file in here
             # which are now discarded
             @files = split(' ', $contents{$key});
             foreach $fi (@files) {
                ($nam, $dir, $ext) = fileparse( $fi, qr/\.[^.]*/ );
                if (is_h_source_ext($ext)) { # FIX20061107 - only IFF a header
                  $file = $base_dir . $relative_dir . '/' . $fi;
                        $file =~ s/\//\\/g; # use DOS path sep
                        $dupe = add_2_source_list( $file, $group );
                }
             }
          }
       }
    }
   
    # process for OTHER THAN LIBRARIES
    # process_other_sources( $makefile . '.am', $rd );
    process_other_sources( $file_am, $rd );

    # per AM file sources
    my $ac_cnt = scalar @am_c_files;
    my $ah_cnt = scalar @am_h_files;
    my $of_cnt = scalar @am_o_files;
    ###prt( "End am file: $dsp_file - ac_cnt=$ac_cnt, ah_cnt=$ah_cnt, from $makefile.am ...\n" ) if ($dbg20);
    prt( "[20] End_am_file: sources C=$ac_cnt, H=$ah_cnt, O=$of_cnt, from [$file_am]\n" ) if ($dbg20);
    $content_by_file{$file_am} = { %contents };

}


sub read_main_am_file {
    my ($amfile, $rd) = @_;
    read_am_file($amfile, $rd);
    my @topdir = ();
    foreach (split(/\//, $relative_dir)) {
        next if $_ eq '.' || $_ eq '';
        if ($_ eq '..') {
            pop @topdir;
        } else {
            push(@topdir, '..');
        }
    }
    @topdir = ('.') if ! @topdir;
    my $top_builddir = join('/', @topdir);
}

sub pre_process_in_file($$) {
    my ($fil,$ra) = @_;
    my ($line,$mac,$m,$nline,$lncnt);
    my @narr = ();
    my %macs = ();
    $lncnt = scalar @{$ra};
    prt("Pre-processing $lncnt lines, from [$fil]...\n");
    foreach $line (@{$ra}) {
        if ($line =~ /^\s*#/) {
            push(@narr,$line);
            next;
        }
        $nline = $line;
        while ($nline =~ /\@(\w+)\@/) {
            $m = $1;
            $mac = "'".$m."'";
            chomp $line;
            if (defined $IN_MACS{$m}) {
                $nline =~ s/\@$m\@/$IN_MACS{$m}/;
            } else {
                prt("Deal with [$mac], in [$line]\n");
                if (defined $macs{$mac}) {
                    $macs{$mac}++;
                } else {
                    $macs{$mac} = 1;
                }
                last;
            }
        }
        push(@narr,$nline);
    }
    my @arr = sort keys(%macs);
    if (@arr) {
        prt("MACS:\n".join(" => '',\n",@arr)."\n");
        $load_log = 1;
        pgm_exit(1,"The ABOVE need to be ADDED to the LIST in IN_MACS!");
    }
    if (length($temp_in_file)) {
        write2file(join("",@narr)."\n",$temp_in_file);
        prtw("WARNING:debug: Written substituded IN file to [$temp_in_file]...\n");
    }
    return @narr;
}

sub trim_rule($) {
    my $rule = shift;
    if (defined $rule && length($rule)) {
        $rule = trim_all($rule);
        while ($rule =~ /\\$/) {
            $rule =~ s/\\$//;
            $rule = trim_all($rule);
        }
        #prt("trim_rule: returning [$rule]\n");
        return $rule;
    }
    #prt("trim_rule: returning blank\n");
    return '';
}

sub read_am_file {
    my ($am_file, $rd) = @_;
    $active_am_file = $am_file;
    ###open( AM_FILE, $am_file ) or mydie( "ERROR: Can't open $am_file: $!\n" );
    ###if ($am_file =~ /^(\\|\/){1}/) {
    ###    $am_file = substr($am_file,1);
    ###}
    if (!open( AM_FILE, $am_file )) {
        prtw( "ERROR: Can't open $am_file: $! \n" );
        return;
    }
    my @am_lines = <AM_FILE>;
    close AM_FILE;
    my $am_lncnt = scalar @am_lines;
    prt( "\nReading [$am_file], $am_lncnt lines (rel_dir=$relative_dir)\n" ) if ($dbg10 || $dbg16 || $dbg19);
    #my ($am_name, $am_path) = fileparse($am_file);
    my ($am_name, $am_path, $am_ext) = fileparse($am_file, qr/\.[^.]*/ );
    @am_lines = pre_process_in_file($am_file,\@am_lines) if ($am_ext =~ /^\.in$/i);
    my $saw_bk = 0;
    my $was_rule = 0;
    my $spacing = '';
    my $comment = '';
    my $last_var_name = '';
    my $blank = 0;
    my $cond_true = 2; # undetermined ...
    my $msg = '';
    my $aml = '';
    my $aln = 0;
    my $ai = 0;
    my $cond_string = '';
    my ($targ,$rule,$type,$value,$add_it,$disc_it);
    my $in_if_pattern = 0;

    # process, line by line ... where $aln is current line
    for ($ai = 0; $ai < $am_lncnt; $ai++) {
        $_ = $am_lines[$ai];
        $aln = $ai + 1;
        if (/$IGNORE_PATTERN/o) {
            # Merely delete comments beginning with two hashes.
        } elsif (/$WHITE_PATTERN/o) {
            # Stick a single white line before the incoming macro or rule.
            $spacing = "\n";
            $blank = 1;
        } elsif (/$COMMENT_PATTERN/o) {
            # Stick comments before the incoming macro or rule.  Make
            # sure a blank line preceeds first block of comments.
            $spacing = "\n" unless $blank;
            $blank = 1;
            $comment .= $spacing . $_;
            $spacing = '';
        } else {
            last;
        }
    }

    $output_vars .= $comment . "\n";
    $comment = '';
    $spacing = "\n";
    my $source_suffix_pattern = '';

    my $is_ok_macro = 0;
    for ( ; $ai < $am_lncnt; $ai++) {
        $_ = $am_lines[$ai];
        $aln = $ai + 1;
        $aml = $am_lines[$ai];
        chomp $aml;
        $aml = trim_all($aml); # clean up line
        $value = trim_rule($aml);
        prt( "$aln [$aml]\n" ) if ($dbg10);
        #if ($aml =~ /^all\s*:/) {
        #    prt("$aln: Got all target [$aml] - set all debug ON! ".($saw_bk ? "saw_bk" : "nobk")."\n");
        #    set_all_dbg_on();
        #}
        # $_ .= "\n" unless substr ($_, -1, 1) eq "\n";
        if ($aml =~ /$IGNORE_PATTERN/o) {
            prt("[dbg35] $aln:[$aml]: IGNORE_PATTERN\n") if ($dbg35);
            # Merely delete comments beginning with two hashes.
        } elsif ($aml =~ /$WHITE_PATTERN/o) {
            prt("[dbg35] $aln:[$aml]: WHITE_PATTERN\n") if ($dbg35);
            # Stick a single white line before the incoming macro or rule.
            $spacing = "\n";
            ###am_line_error ($aln, "blank line following trailing backslash") if $saw_bk;
            am_line_error ($aln, "blank line following trailing backslash") if $saw_bk;
        } elsif ($aml =~ /$COMMENT_PATTERN/o) {
            prt("[dbg35] $aln:[$aml]: COMMENT_PATTERN\n") if ($dbg35);
            # Stick comments before the incoming macro or rule.
            $comment .= $spacing . $aml;
            $spacing = '';
            if ($error_comment_saw_bk) {
                ###am_line_error ($aln, "comment following trailing backslash") if $saw_bk;
                am_line_error ($aln, "comment following trailing backslash") if $saw_bk;
            }
            next;
        } elsif ($saw_bk) {
            prt("[dbg35] $aln:[$aml]: saw back - continuation line\n") if ($dbg35);
            # ============================================================
            # continuation of previous line(s) ...
            if ($was_rule) {
                prt("[dbg35] $aln: was_rule - add to output_trailer, and targ [$targ]\n") if ($dbg35);
                $output_trailer .= join ('', @conditional_stack) . $aml;
                if (defined $contents{$targ}) {
                    if (length($value)) {
                        $contents{$targ} .= " $value";
                        prt("[dbg46] Added to contents:1: [$targ]=[$value]\n") if ($dbg46);
                    }
                } else {
                    prtw("WARNING: contents{$targ} does NOT EXITS!\n");
                }
                $saw_bk = ($aml =~ /\\$/);
            } else {
                prt("[dbg35] $aln: !was_rule last var [$last_var_name]\n") if ($dbg35);
                $saw_bk = ($aml =~ /\\$/);
                # Chop newline and backslash if this line is
                # continued.  ensure trailing whitespace exists.
                #chop if $saw_bk;
                #chop if $saw_bk;
                # decide if to be added to 'contents' ...
                $add_it = 0;     # assume NO
                $disc_it = 0;    # also NO
                if ( defined $contents{$last_var_name} ) {
                    if ( @conditional_stack ) {
                        if ( $conditional_stack[$#conditional_stack] =~ /_TRUE\@$/ ) {
                            # we are in the if TRUE state
                            if ($cond_true == 1) {
                                $add_it = 1;
                            } else {
                                $disc_it = 1;
                            }
                        } else {
                            # we are in a FALSE state
                            if ($cond_true != 1) {
                                $add_it = 1;
                            } else {
                                $disc_it = 1;
                            }
                        }
                    } else { 
                        ###prt( "No conditional stack for this macro! lv=[$last_var_name] ".
                        ###    "add_it\n" ) if ($dbg11);
                        $add_it = 1; # so add it
                    }
                } else { # NO contents for this var
                    prt( "NO contents for [$last_var_name]! ".
                        "Technical this is an ERROR, but for now add_it...\n" ) if ($dbg11);
                    $add_it = 1;
                }

                if ($add_it) {
                    $contents{$last_var_name} .= ' ' unless $contents{$last_var_name} =~ /\s$/;
                    $contents{$last_var_name} .= $value;    # $aml;

                    if (@conditional_stack) {
                        prt("[dbg46] Added to contents:2: [$last_var_name]=[$value], and to conditional quoted...\n") if ($dbg46);
                        $conditional{$last_var_name} .= quote_cond_val ($value);
                    } else {
                        prt("[dbg46] Added to contents:2: [$last_var_name]=[$value]\n") if ($dbg46);
                    }
                    prt("[dbg12] $aln:End VAR:[$last_var_name] = [".trim_line($contents{$last_var_name})."]...\n" ) if ( !$saw_bk && $dbg12);
                } else {
                    if (!$disc_it) {
                        # that is, if NOT a deliberate discard
                        ###push(@warnings, "WARNING: File [$am_file], line $aln, last var [$last_var_name]");
                        push(@warnings, "WARNING: File [$am_file], line $aln, last var [$last_var_name]");
                        push(@warnings, " Discarding the [$aml] ... CHECK ME");
                        if ( defined $contents{$last_var_name} ) {
                            if ( @conditional_stack ) {
                                push(@warnings, " stack = $conditional_stack[$#conditional_stack] cond_true=$cond_true");
                            }
                        }
                        prtw( "WARNING:1: Discarding this [$aml] ... CHECK ME!\n" );
                    } else {
                        prtw( "WARNING:2: Discarding this [$aml] ... CHECK ME!\n" );
                    }
                }
            }
            # ===================================================================
        } elsif ($aml =~ /$IF_PATTERN/o) {
            prt("[dbg35] $aln:[$aml]: IF_PATTERN\n") if ($dbg35);
            if ( defined $configure_cond{$1} ) {
                ###if ( defined $cfg_defines{$1} )
                if ($configure_cond{$1} == 2) {
                    prt( "Found if $1, and condition is TRUE (see cfg_defines) ...\n" ) if ($dbg13);
                    $cond_true = 1;
                } else {
                    prt( "Found if $1, but NOT in cfg_defines ...\n" ) if ($dbg13);
                    $cond_true = 0;
                }
            } else {
               # 2009-06-09 - change to a WARNING only
               ###am_line_error ($aln, "Line $aln: [$aml]\n[$1] does not appear in AM_CONDITIONAL!");
               prtw("WARNING: Line $aln: [$aml] [$1] does not appear in AM_CONDITIONAL!\n");
            }
            push (@conditional_stack, "\@" . $1 . "_TRUE\@");
            $in_if_pattern++;
        } elsif ($aml =~ /$ELSE_PATTERN/o) {
            prt("[dbg35] $aln:[$aml]: ELSE_PATTERN\n") if ($dbg35);
            if (! @conditional_stack) {
                am_line_error ($aln, "else without if");
            } elsif ($conditional_stack[$#conditional_stack] =~ /_FALSE\@$/) {
                am_line_error ($aln, "else after else");
            } else {
                $conditional_stack[$#conditional_stack] =~ s/_TRUE\@$/_FALSE\@/;
            }
        } elsif ($aml =~ /$ENDIF_PATTERN/o) {
            prt("[dbg35] $aln:[$aml]: ENDIF_PATTERN\n") if ($dbg35);
            if (! @conditional_stack) {
                am_line_error ($aln, ": endif without if");
            } else {
                pop @conditional_stack;
            }
            $cond_true = 2; # undetermined ...
            $in_if_pattern-- if ($in_if_pattern);
        } elsif ($aml =~ /$RULE_PATTERN/o) {
            # Found a rule, and may be many lines...
            prt("[dbg35] $aln:[$aml]: RULE_PATTERN [$1] [$2]\n") if ($dbg35);
            $targ = $1;
            $rule = trim_rule($2);
            $was_rule = 1;
            if (defined $contents{$targ} &&
                (@conditional_stack ? ! defined $conditional{$targ} : defined $conditional{$targ})) {
                $msg = "[$targ] RULE_PATTERN defined both conditionally and unconditionally.\n";
                $value = $contents{$targ};
                $msg .= "Defined in contents with value [$value]\n";
                if (@conditional_stack) {
                    $value = join(", ",@conditional_stack);
                    $msg .= "There is a conditional_stack, with [$value], but NOT in conditional\n";
                } else {
                    $value = $conditional{$targ};
                    $msg .= "There is NO conditional_stack open, but is defined in conditional as [$value]\n";
                }
                $msg .= "So what is WRONG?";
                if ($abort_on_conditional) {
                    am_line_error ($aln, $msg);
                } else {
                    prtw("WARNING:$aln: $msg CHECK ME!\n");
                }
            }
            # 2010-09-29: NO VALUE MATTERS Value here doesn't matter; for targets we only note existence.
            if (defined $contents{$targ}) {
                $contents{$targ} .= ' '.$rule;
            } else {
                $contents{$targ} = $rule;
            }
            if (defined $targets{$targ}) {
                $targets{$targ} .= ' '.$rule;
                prt("[dbg46] Added to contents:3: [$targ]=[$rule]\n") if ($dbg46);
            } else {
                $targets{$targ} = $rule;
                prt("[dbg46] Added to contents:3: [$targ]=[$rule] SET\n") if ($dbg46);
            }
            $cond_string = join ('', @conditional_stack);
            if (@conditional_stack) {
                if ($conditional{$targ}) {
                    check_ambiguous_conditional ($targ, $cond_string);
                    $conditional{$targ} .= ' ';
                } else {
                    $conditional{$targ} = '';
                }
                $conditional{$targ} .= $cond_string . ' 1';
            }
            $content_lines{$targ} = $aln;
            $output_trailer .= $comment . $spacing . $cond_string . $aml;
            $comment = $spacing = '';
            $saw_bk = ($aml =~ /\\$/);

            # Check the rule for being a suffix rule. If so, store in
            # a hash.
            my $source_suffix;
            my $object_suffix;

            if (defined $1 && length($1) && (($source_suffix, $object_suffix) = ($1 =~ $SUFFIX_RULE_PATTERN))) {
                $suffix_rules{$source_suffix} = $object_suffix;
                prt("[dbg17] Sources ending in .$source_suffix become .$object_suffix\n" ) if $dbg17;
                $source_suffix_pattern = "(" . join('|', keys %suffix_rules) . ")";
            }

            # FIXME: make sure both suffixes are in SUFFIXES? Or set
            # SUFFIXES from suffix_rules?

        } elsif (($is_ok_macro = /$MACRO_PATTERN/o) || /$BOGUS_MACRO_PATTERN/o) {
            # 2010-08-26 - especially when process Makefile.in, can have
            # @ON_WINDOWS@LINK = $(CC) $(LDFLAGS) -I. -I$(top_srcdir) -L.libs
            #} elsif (($is_ok_macro = ($aml =~ /$MACRO_PATTERN/o)) ||
            #($is_ok_macro = ($aml =~ /$BOGUS_MACRO_PATTERN/o))) {
            prt("[dbg35] $aln:[$aml]: MACRO_PATTERN\n") if ($dbg35);
            prt( "[dbg14] line $aln: Found a macro definition. 1[$1] 2[$2] 3[$3] ...\n" ) if ($dbg14);
            $was_rule = 0;
            $last_var_name = $1;
            $type = $2;
            $value = trim_rule($3);
            if (defined $contents{$last_var_name} &&
               (@conditional_stack ? !defined $conditional{$last_var_name} : defined $conditional{$last_var_name})) {
               prt( "POTENTIAL ERROR: Found a macro definition. 1[$last_var_name] 2[$type] 3[$value] ...\n" );
               if (@conditional_stack) {
                  prt( "Conditional stack: $conditional_stack[-1]" );
               } else {
                  prt( "NO Conditional stack: " );
               }
               if (defined $conditional{$last_var_name}) {
                  prt( " Value = $conditional{$last_var_name}" );
               } else {
                  prt( " No conditional" );
               }
               prt(" IGNORED\n");
               #am_line_error ($last_var_name, "$last_var_name $aln: if MACRO_PATTERN defined both conditionally and unconditionally");
            }
            if (($value ne '') && (substr($value, -1) eq "\\")) {
                $value = substr($value, 0, length($value) - 1);
            }
            if ($type eq '+') {
                if (! defined $contents{$last_var_name} && defined $configure_vars{$last_var_name}) {
                    $contents{$last_var_name} = '@' . $last_var_name . '@';
                }
                if ( defined $contents{$last_var_name} ) {
                    $contents{$last_var_name} .= ' ' . $value;
                    prt("[dbg46] Added to contents:4: [$last_var_name]=[$value]\n") if ($dbg46);
                } else {
                    $contents{$last_var_name} = $value;
                    prt("[dbg46] Added to contents:4: [$last_var_name]=[$value] SET\n") if ($dbg46);
                }
            } else {
                if ( defined $contents{$last_var_name} ) {
                    if ( @conditional_stack ) {
                        if ( $conditional_stack[$#conditional_stack] =~ /_TRUE\@$/ ) {
                            # we are in the if TRUE state
                            if ($cond_true == 1) {
                                if ($dbg15) {
                                    if ( $contents{$last_var_name} ne $value ) {
                                        prt( "NB: [$last_var_name] = [$contents{$last_var_name}]" .
                                            " replaced with [$value] (am_file=$am_file line=$aln)".
                                            (($aml =~ /\\$/) ? "saw_bk" : "end") . "\n" );
                                    }
                                }
                                $contents{$last_var_name} = $value;
                                prt("[dbg46] Added to contents:5: [$last_var_name]=[$value] SET\n") if ($dbg46);
                                $content_lines{$last_var_name} = $aln;
                            }
                        } else {
                            # we are in the else FALSE state
                            if ($cond_true != 1) {
                                if ($dbg15) {
                                    if ( $contents{$last_var_name} ne $value ) {
                                        prt( "NB: [$last_var_name] = [$contents{$last_var_name}]" .
                                            " replaced with [$value] (am_file=$am_file line=$aln)".
                                            (($aml =~ /\\$/) ? "saw_bk" : "end") . "\n" );
                                    }
                                }
                                $contents{$last_var_name} = $value;
                                prt("[dbg46] Added to contents:6: [$last_var_name]=[$value] SET\n") if ($dbg46);
                                $content_lines{$last_var_name} = $aln;
                            }
                        }
                    }
                } else {
                    prt( "First setting [$last_var_name] = [$value] " .
                        "(am_file=$am_file line=$aln) ".
                        (($aml =~ /\\$/) ? "saw_bk" : "end") . "\n" ) if ($dbg15);
                    $contents{$last_var_name} = $value;
                    prt("[dbg46] Added to contents:7: [$last_var_name]=[$value] SET\n") if ($dbg46);
                    # The first assignment to a macro sets the line
                    # number.  Ideally I suppose we would associate line
                    # numbers with random bits of text.
                    $content_lines{$last_var_name} = $aln;
                }
            }
            $cond_string = join ('', @conditional_stack);
            if (@conditional_stack) {
                my $found = 0;
                my $val;
                if ($conditional{$last_var_name}) {
                    if ($type eq '+') {
                        # If we're adding to the conditional, and it
                        # exists, then we might want to simply replace
                        # the old value with the new one.
                        my (@new_vals, @cond_vals);
                        @cond_vals = split (' ', $conditional{$last_var_name});
                        while (@cond_vals) {
                            my $vcond = shift (@cond_vals);
                            push (@new_vals, $vcond);
                            if (conditional_same ($vcond, $cond_string)) {
                                $found = 1;
                                $val = (unquote_cond_val (shift (@cond_vals)) . ' ' . $value);
                                push (@new_vals, quote_cond_val ($val));
                            } else {
                                push (@new_vals, shift (@cond_vals));
                            }
                        }
                        if ($found) {
                            $conditional{$last_var_name} = join (' ', @new_vals);
                        }
                    }

                    if (! $found) {
                        check_ambiguous_conditional ($last_var_name, $cond_string);
                        $conditional{$last_var_name} .= ' ';
                        $val = $value;
                    }
                } else {
                    $conditional{$last_var_name} = '';
                    $val = $contents{$last_var_name};
                }
                if (! $found) {
                    $conditional{$last_var_name} .= ($cond_string . ' ' . quote_cond_val ($val));
                }
            }
            # FIXME: this doesn't always work correctly; it will group
            # all comments for a given variable, no matter where
            # defined.
            $am_vars{$last_var_name} = $comment . $spacing;
            $def_type{$last_var_name} = ($type eq ':') ? ':' : '';
            push (@var_list, $last_var_name);
            $comment = $spacing = '';
            $saw_bk = ($aml =~ /\\$/);

            # Error if bogus.
            am_line_error ($aln, "bad macro name \`$last_var_name'") if (!$is_ok_macro && $exit_bogus_macro);
        } elsif ($aml =~ /$INCLUDE_PATTERN/o) {
            my $orgpath = $1;
            prt("[dbg35] $aln:[$aml]: INCLUDE_PATTERN\n") if ($dbg35);
            my $path = $orgpath;
            if ($path =~ s/^\$\(top_srcdir\)\///) {
                push (@include_stack, "\$\(top_srcdir\)/$path");
            } else {
                $path =~ s/\$\(srcdir\)\///;
                push (@include_stack, "\$\(srcdir\)/$path");
                $path = $relative_dir . "/" . $path;
            }
            if ($path =~ /^\//) {
                $path = substr($path,1);
            }
            if (! -f $path) {
                my $ff = $relative_dir . "/" . $path;
                if (-f $ff) {
                    $path = $ff;
                } else {
                    $ff = $rd . $path;
                    if (-f $ff) {
                        $path = $ff;
                    } else {
                        prtw( "WARNING: in [$am_file] - Include WILL FAIL! [$orgpath] ...\n" );
                        prtw( "  Last try was $ff ...\n" );
                    }
                }
            }
            read_am_file ($path, $rd);
            $active_am_file = $am_file;
        } else {
            prt("[dbg35] $aln:[$aml]: UNCASED PATTERN\n") if ($dbg35);
            # This isn't an error; it is probably a continued rule.
            # In fact, this is what we assume.
            $was_rule = 1;
            $output_trailer .= ($comment . $spacing . join ('', @conditional_stack) . $aml);
            $comment = $spacing = '';
            $saw_bk = ($aml =~ /\\$/);
            prt("$aln: UNCASED LINE! [$aml]! ASSUMED was_rule continuations? CHECK ME! ".($saw_bk ? "saw_bk" : "nobk")."\n") if ($dbg36);
        }
    }

    prt( "Done reading of $am_file\n" ) if ($dbg10 || $dbg16 || $dbg19);
    $output_trailer .= $comment;

    am_error ("unterminated conditionals: " . join (' ', @conditional_stack)) if (@conditional_stack);
    $act_am_file = $am_file;
    $act_am_dir = $am_path;
    $act_am_ext = $am_ext;
}


sub add_2_source_list {
    my ($fil, $grp) = @_;
    my ($ft, $dir, $fe) = fileparse( $fil, qr/\.[^.]*/ );
    my $src = ($grp . '|' . $fil . '|' . $ft);
    my $ret = 0;
    if ( is_c_source_ext($fe) ) {
        prt( "Add $src to C list\n" ) if $dbg18;
        push(@msvc_c_files, $src);
        foreach my $tt (@msvc_titles) {
            # just to deal with duplicate names
            if( $tt eq $ft ) {
                $ret = 1;
                last;
            }
        }
        push(@msvc_titles, $ft);
        push(@am_c_files, $src);
    } elsif ( is_h_source_ext($fe) ) {
        prt( "Add $src to H list\n" ) if $dbg18;
        push(@msvc_h_files, $src);
        push(@am_h_files, $src);
    } else {
        prt( "Add $src to OTHER list\n" ) if $dbg18;
        push(@msvc_o_files, $src);
        push(@am_o_files, $src);
    }
    return $ret;
}

# Quote a value in order to put it in $conditional.  We need to quote
# spaces, and we need to handle null strings, so that we can later
# retrieve values by splitting on space.
sub quote_cond_val {
    my ($val) = @_;
    $val =~ s/ /\001/g;
    $val =~ s/\t/\003/g;
    $val = "\002" if $val eq '';
    return $val;
}

# this function seems MISSING - maybe never used!
sub unquote_cond_val {
    my ($val) = @_;
    $val =~ s/\001/ /g;
    $val =~ s/\003/\t/g;
    $val = '' if $val eq "\002";
    return $val;
}

# See if a conditional is true.  Both arguments are conditional
# strings.  This returns true if the first conditional is true when
# the second conditional is true.
sub conditional_true_when {
    my ($cond, $when) = @_;

    # Check the easy case first.
    if ($cond eq $when) {
        return 1;
    }

    # Check each component of $cond, which looks @COND1@@COND2@.
    foreach my $comp (split ('@', $cond)) {
        # The way we split will give null strings between each condition.
        next if ! $comp;
        if (index ($when, '@' . $comp . '@') == -1) {
            return 0;
        }
    }
    return 1;
}

# Check for an ambiguous conditional.  This is called when a variable
# or target is being defined conditionally.  If we already know about
# a definition that is true under the same conditions, then we have an
# ambiguity.
sub check_ambiguous_conditional {
    my ($var_name, $cond) = @_;
    my (@cond_vals) = split (' ', $conditional{$var_name});
    while (@cond_vals) {
        my ($vcond) = shift (@cond_vals);
        shift (@cond_vals);
        if (conditional_true_when ($vcond, $cond) || conditional_true_when ($cond, $vcond)) {
            prt( "$var_name multiply defined in condition\n" );
        }
    }
}

sub trim_line {
    my ($l) = shift;
    chomp $l;
    $l =~ s/\r$//; # and remove CR, if present
    $l =~ s/\t/ /g; # tab to space
    $l =~ s/\s\s/ /g while ($l =~ /\s\s/);    # double space to single
    for ($l) {    # trim leading and trailing spaces
        s/^\s+//;
        s/\s+$//;
    }
    return $l;
}


sub mark_all_files {
    my ($f) = shift;
    my $lcf = lc($f);
    #                   0    1    2  3     4
    # push(@all_files, [$df, $ff, 0, $typ, $rd]) if ($typ);
    my $ac = scalar @all_files;
    for (my $i = 0; $i < $ac; $i++) {
        my $tf = lc($all_files[$i][1]);
        if ($tf eq $lcf) {
            my $ct = $all_files[$i][2];
            $ct++;
            $all_files[$i][2] = $ct;
            return 1;
        }
    }
    return 0;
}

sub list_all_sources {
    my ($msg,$rd) = @_;
    my $ac = scalar @all_files;
    my ($mc,$file,$done,$type,$rfil,$len,$max,$i);
    $mc = 0;
    $max = 0;
    #                  0    1    2  3     4
    #push(@all_files, [$df, $ff, 0, $typ, $rd]) if ($typ);
    for ($i = 0; $i < $ac; $i++) {
        $rfil = $all_files[$i][0];
        $done = $all_files[$i][2];
        $mc++ if (!$done);
        $len = length($rfil);
        $max = $len if ($len > $max);
    }
    if ($mc) {
        prt("First a list of $mc of $ac NOT done...\n");
        for ($i = 0; $i < $ac; $i++) {
            $rfil = $all_files[$i][0];
            $file = $all_files[$i][1];
            $done = $all_files[$i][2];
            $type = $all_files[$i][3];
            if (!$done) {
                prt("File:".get_my_type_stg($type).": $rfil\n");
            }
        }
    }
    if ($ac - $mc) {
        prt("Next a list of ".($ac - $mc)." of $ac done...\n");
        for ($i = 0; $i < $ac; $i++) {
            $rfil = $all_files[$i][0];
            $file = $all_files[$i][1];
            $done = $all_files[$i][2];
            $type = $all_files[$i][3];
            if ($done) {
                prt("File:".get_my_type_stg($type).": $rfil\n");
            }
        }
    }
}


sub show_source_list {
    my ($msg,$rd) = @_;
    my $ac = scalar @all_files;
    #                  0    1    2  3     4
    #push(@all_files, [$df, $ff, 0, $typ, $rd]) if ($typ);
    my ($mc, $i, $file, $line, $omsg);
    $mc = 0;
    my @files = ();
    my ($nam, $dir, $ext);
    if (!$ac) {
        prt("No SOURCES to show!\n");
        return;
    }
    if ($show_all_sources) {
        list_all_sources($msg,$rd);
        return;
    }
    # get count of MISSING items
    for ($i = 0; $i < $ac; $i++) {
        if ($all_files[$i][3] == $TYPE_C) {
            if ($all_files[$i][2] == 0) {
                $mc++;
            }
        }
    }
    if ($mc) {
        prt( "\nSources found, but MISSED - $mc ...root = $rd\n" );
        for ($i = 0; $i < $ac; $i++) {
            if ($all_files[$i][3] == $TYPE_C) {
                if ($all_files[$i][2] == 0) {
                    $file = $all_files[$i][1];
                    $omsg = " ".sub_common_folder($file, $rd)." ";
                    $omsg = get_main_msg($file,sub_common_folder($file,$rd),1,"") if ($check4main2); # check if a main()
                    prt( "$omsg\n" );
                    push(@files, $file) if ($recheck_am);
                }
            }
        }
        prt( "Above $mc Sources NOT INCLUDED in $msg ...\n\n" );
        if ($recheck_am) {
            my @makes = get_all_makes();
            $mc = 0;
            foreach my $mk (@makes) {
                if (open MK, "<$mk") {
                    my @lines = <MK>;
                    close MK;
                    foreach $file (@files) {
                        if ($check_full) {
                            ($nam, $dir) = fileparse($file);
                            foreach $line (@lines) {
                                chomp $line;
                                if ($line =~ /$nam/) {
                                    prt( "Note: [$nam] is in [$mk] ... line[$line]\n" );
                                    $mc++;
                                    last;
                                }
                            }
                        } else {
                            ($nam, $dir, $ext) = fileparse( $file, qr/\.[^.]*/ );
                            foreach $line (@lines) {
                                chomp $line;
                                if ($line =~ /$nam/) {
                                    prt( "Note: [$nam] is in [$mk] ... line[$line]\n" );
                                    $mc++;
                                    last;
                                }
                            }
                        }
                    }
                }
            }
            if ($mc) {
                prt( "Above $mc references should be checked ...\n\n" );
            }
        }
    }
}

sub get_missed_makes {
    my ($rd) = shift;
    my $ac = scalar @all_files;
    my $i = 0;
    my @mam = ();
    for ($i = 0; $i < $ac; $i++) {
        if ($all_files[$i][3] == $TYPE_AM) {
            if ($all_files[$i][2] == 0) {
                my $file = $all_files[$i][1];    # get FULL (qualified) path name
                my ($nm, $path) = fileparse($file);    # split it to name,path
                #my $rp = unix_2_dos(get_relative_path( $path, $rd ).$nm);
                my $rp = unix_2_dos(get_relative_path_2( $path, $rd ).$nm);
                push( @mam, $rp );    # pass back the DOS relative makefile.am entry
            }
        }
    }
    return @mam;
}

sub get_all_makes {
    my $ac = scalar @all_files;
    my $i = 0;
    my @mam = ();
    for ($i = 0; $i < $ac; $i++) {
        if ($all_files[$i][3] == $TYPE_AM) {
            my $file = $all_files[$i][1];    # get FULL (qualified) path name
            ###my ($nm, $path) = fileparse($file);    # split it to name,path
            push( @mam, $file );    # pass back makefile.am full path
        }
    }
    return @mam;
}

########################################################################
####### ONLY DSP STUFF

sub expand_here {
    local $_ = shift;
    s/\%cflags\%/$msvc_cflags/g;
    s/\%libs\%/$msvc_libs/g;
    s/\%dlibs\%/$msvc_dlibs/g;
    s/\%rlibs\%/$msvc_rlibs/g;
    return $_;
}

sub console_app_dsp_init {
    my ($name, $dsp_name) = @_;
    prt( "Creating console app type $dsp_name ...\n" );
    my $ren = rename_2_old_bak( $dsp_name );
    if ($ren) {
        prt( "Renamed original to ".(($ren == 1) ? "OLD" : "BAK")." ...\n" );
    }
    open(DSP, ">$dsp_name") || mydie( "ERROR: Can't create $dsp_name: $!\n" );

    print DSP expand_here(<<EOF);
# Microsoft Developer Studio Project File - Name="$name" - Package Owner=<4>
# Microsoft Developer Studio Generated Build File, Format Version 6.00
# ** DO NOT EDIT **

# TARGTYPE "Win32 (x86) Console Application" 0x0103

CFG=$name - Win32 Debug
!MESSAGE This is not a valid makefile. To build this project using NMAKE,
!MESSAGE use the Export Makefile command and run
!MESSAGE 
!MESSAGE NMAKE /f "$name.mak".
!MESSAGE 
!MESSAGE You can specify a configuration when running NMAKE
!MESSAGE by defining the macro CFG on the command line. For example:
!MESSAGE 
!MESSAGE NMAKE /f "$name.mak" CFG="$name - Win32 Debug"
!MESSAGE 
!MESSAGE Possible choices for configuration are:
!MESSAGE 
!MESSAGE "$name - Win32 Release" (based on "Win32 (x86) Console Application")
!MESSAGE "$name - Win32 Debug" (based on "Win32 (x86) Console Application")
!MESSAGE 

# Begin Project
# PROP AllowPerConfigDependencies 0
# PROP Scc_ProjName ""
# PROP Scc_LocalPath ""
CPP=cl.exe
RSC=rc.exe

!IF  "\$(CFG)" == "$name - Win32 Release"

# PROP Use_MFC 0
# PROP Use_Debug_Libraries 0
# PROP Output_Dir "Release"
# PROP Intermediate_Dir "Release"
# PROP Target_Dir ""
# ADD CPP /nologo /W3 /GR /GX /O2 /D "NDEBUG" /D "WIN32" /D "_CONSOLE" /D "_MBCS" /FD /c %cflags%
# SUBTRACT CPP /YX
# ADD RSC /l 0xc09 /d "NDEBUG"
BSC32=bscmake.exe
# ADD BSC32 /nologo
LINK32=link.exe
# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ws2_32.lib /nologo /subsystem:console /machine:I386 %libs% %rlibs%

!ELSEIF  "\$(CFG)" == "$name - Win32 Debug"

# PROP Use_MFC 0
# PROP Use_Debug_Libraries 1
# PROP Output_Dir "Debug"
# PROP Intermediate_Dir "Debug"
# PROP Ignore_Export_Lib 0
# PROP Target_Dir ""
# ADD CPP /nologo /W3 /Gm /GR /GX /ZI /Od /D "_DEBUG" /D "WIN32" /D "_CONSOLE" /D "_MBCS" /FD /GZ /c %cflags%
# ADD RSC /l 0xc09 /d "_DEBUG"
BSC32=bscmake.exe
# ADD BSC32 /nologo
LINK32=link.exe
# ADD LINK32 kernel32.lib user32.lib winspool.lib comdlg32.lib gdi32.lib shell32.lib advapi32.lib ws2_32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept %libs% %dlibs%

!ENDIF 

# Begin Target

# Name "$name - Win32 Release"
# Name "$name - Win32 Debug"
EOF

    close(DSP);
}

sub static_lib_dsp_init {
    my ($name, $dsp_name) = @_;
    prt( "Creating static library type $dsp_name ... \n" );
    my $ren = rename_2_old_bak( $dsp_name );
    if ($ren) {
        prt( "Renamed original to ".(($ren == 1) ? "OLD" : "BAK")." ...\n" );
    }
    open(DSP, ">$dsp_name") || mydie( "ERROR: Can't create $dsp_name: $!\n" );

    print DSP expand_here(<<EOF);
# Microsoft Developer Studio Project File - Name="$name" - Package Owner=<4>
# Microsoft Developer Studio Generated Build File, Format Version 6.00
# ** DO NOT EDIT **

# TARGTYPE "Win32 (x86) Static Library" 0x0104

CFG=$name - Win32 Debug
!MESSAGE This is not a valid makefile. To build this project using NMAKE,
!MESSAGE use the Export Makefile command and run
!MESSAGE 
!MESSAGE NMAKE /f "$name.mak".
!MESSAGE 
!MESSAGE You can specify a configuration when running NMAKE
!MESSAGE by defining the macro CFG on the command line. For example:
!MESSAGE 
!MESSAGE NMAKE /f "$name.mak" CFG="$name - Win32 Debug"
!MESSAGE 
!MESSAGE Possible choices for configuration are:
!MESSAGE 
!MESSAGE "$name - Win32 Release" (based on "Win32 (x86) Static Library")
!MESSAGE "$name - Win32 Debug" (based on "Win32 (x86) Static Library")
!MESSAGE 

# Begin Project
# PROP AllowPerConfigDependencies 0
# PROP Scc_ProjName ""
# PROP Scc_LocalPath ""
CPP=cl.exe
RSC=rc.exe

!IF  "\$(CFG)" == "$name - Win32 Release"

# PROP Use_MFC 0
# PROP Use_Debug_Libraries 0
# PROP Output_Dir "Release"
# PROP Intermediate_Dir "Release"
# PROP Target_Dir ""
# ADD CPP /nologo /W3 /GR /GX /O2 /D "NDEBUG" /D "WIN32" /D "_MBCS" /FD /c %cflags%
# ADD RSC /l 0x409 /d "NDEBUG"
BSC32=bscmake.exe
# ADD BASE BSC32 /nologo
# ADD BSC32 /nologo
LINK32=link.exe -lib
# ADD BASE LIB32 /nologo
# ADD LIB32 /nologo

!ELSEIF  "\$(CFG)" == "$name - Win32 Debug"

# PROP Use_MFC 0
# PROP Use_Debug_Libraries 1
# PROP Output_Dir "Debug"
# PROP Intermediate_Dir "Debug"
# PROP Target_Dir ""
# ADD CPP /nologo /W3 /Gm /GR /GX /ZI /Od /D "_DEBUG" /D "WIN32" /D "_MBCS" /FD /GZ /c %cflags%
# ADD RSC /l 0x409 /d "_DEBUG"
BSC32=bscmake.exe
# ADD BASE BSC32 /nologo
# ADD BSC32 /nologo
LINK32=link.exe -lib
# ADD BASE LIB32 /nologo
# ADD LIB32 /nologo

!ENDIF 

# Begin Target

# Name "$name - Win32 Release"
# Name "$name - Win32 Debug"
# Begin Group "Source Files"

# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat;cc"
EOF

    close(DSP);
}

# This END this DSP file,
# but first it also WRITES the HEADERS, if any found
sub end_dsp_file {
    my ($fil) = shift;
    if (open DSP, ">>$fil") {
      print DSP "# End Group\n";
      # just the HEADER files - SHOULD ACCUMULATE THEM FOR HERE
      print DSP "# Begin Group \"Header Files\"\n";
      print DSP "\n";
      print DSP "# PROP Default_Filter \"h;hpp;hxx;hm;inl\"\n";
      # 2009-06-09 Add HEADERS if any found
      if (defined $am_headers{$last_project}) {
          my $lsrcs = $am_headers{$last_project};
          my @arr = split(/\|/ , $lsrcs);    # Sources
          foreach my $s (@arr) {
             $s = loc_fix_rel($s);
             print DSP "# Begin Source File\n";
             print DSP "\n";
             print DSP "SOURCE=$s\n";
             print DSP "# End Source File\n";
         }
      } else {
         print DSP "\n";
      }
      print DSP "# End Group\n";
      print DSP "# End Target\n";
      print DSP "# End Project\n";
      close(DSP);
      prt( "[dbg30] Ending last DSP - [$fil] ...\n" ) if ($dbg30);
    }
}

sub get_am_incs {
    my ($incs, $prj) = @_;
    my $ics = '';
    my @pths = ();
    my $ic = '';
    if (defined $am_includes{$prj}) {
        $ics = $am_includes{$prj};
        @pths = split(' ',$ics);
        foreach $ic (@pths) {
            $incs .= " " if (length($incs));
            $incs .= "/I \"$ic\"";    # could go for RELATIVE DIRECTORY
        }
    }
    if (defined $am_cppflags{$prj}) {
        $ics = $am_cppflags{$prj};
        @pths = split(' ',$ics);
        foreach $ic (@pths) {
            $incs .= " " if (length($incs));
            $incs .= "/D \"$ic\"";
        }
    }

   # 2009-05-09 - ensure _CRT_SECURE_NO_DEPRECATE is added
   if ($add_CRT_SECURE_NO_DEPRECATE) {
      if ( !($incs =~ /_CRT_SECURE_NO_DEPRECATE/) ) {
            $incs .= " " if !($incs =~ /\s$/);
         $incs .= "/D \"_CRT_SECURE_NO_DEPRECATE\"";
      }
   }
   if ($add_CONFIG_H) {
      if ( !($incs =~ /HAVE_CONFIG_H/) ) {
            $incs .= " " if !($incs =~ /\s$/);
         $incs .= "/D \"HAVE_CONFIG_H\"";
      }
   }
   if ($add_NOMINMAX) {
      if ( !($incs =~ /NOMINMAX/) ) {
            $incs .= " " if !($incs =~ /\s$/);
         $incs .= "/D \"NOMINMAX\"";
      }
   }

    return $incs;
}

sub get_am_libs {
    my ($incs,$prj) = @_;
    if (defined $am_libadds{$prj}) {
        $incs .= " " if (length($incs));
        $incs .= $am_libadds{$prj};
    }
    return $incs;
}

# write DSP file
sub out_dsp_file {
    my ($prj, $fil, $src, $rd, $typ) = @_;
    my ($dsptype, $srcdir, $shtfil);
    if ($prj ne $last_project) {
        end_dsp_file($last_dsp_file) if (length($last_dsp_file));
        $last_project = $prj;
        $last_dsp_file = $fil;
        $msvc_cflags = get_am_incs( $msvc_cflags, $prj );
        $msvc_libs = get_am_libs( $msvc_libs, $prj );
        if ($typ) {
            static_lib_dsp_init( $prj, $fil );
            $dsptype = 'static lib';
        } else {
            console_app_dsp_init( $prj, $fil );
            $dsptype = 'console app';
        }
        $shtfil = subract_target_dir($fil);
        prtd( "Started new DSP $shtfil, project $prj, type $dsptype ...\n" );
    }

    if (open OF, ">>$fil") {
        print OF "# Begin Source File\n";
        print OF "\n";
        $srcdir = $src;
        # This has already been done before here
        #if ($add_SOURCE_REL && length($src_relative)) {
        #   $srcdir = $src_relative;
        #   $srcdir .= "\\" if (! (($srcdir =~ /(\\|\/)$/) || ($src =~ /^(\\|\/)/)) );
        #   $srcdir .= "$src";
        #}
        print OF "SOURCE=$srcdir\n";
        print OF "# End Source File\n";
        close OF;
    }
}

# RENAME A FILE TO .OLD, or .BAK
# 0 - do nothing if file does not exist.
# 1 - rename to .OLD if .OLD does NOT exist
# 2 - rename to .BAK, if .OLD already exists,
# 3 - deleting any previous .BAK ...
sub local_rename_2_old_bak {
    my ($fil) = shift;
    my $ret = 0;
    if ( -f $fil ) {
        my ($nm,$dir,$ext) = fileparse( $fil, qr/\.[^.]*/ );
        my $nmbo = $dir . $nm . '.old';
        $ret = 1;
        if ( -f $nmbo) {
            $ret = 2;
            $nmbo = $dir . $nm . '.bak';
            if ( -f $nmbo ) {
                $ret = 3;
                unlink $nmbo;
            }
        }
        rename $fil, $nmbo;
    }
    return $ret;
}

sub C_comment_starts {
    my ($txt) = shift;
    my $len = length($txt);
    my $ptxt = '';
    my $ttxt = '';
    my ($k, $ch, $pch, $k2, $nch);
    for ($k = 0; $k < $len; $k++) {
        $k2 = $k + 1;
        $ch = substr($txt,$k,1);
        $nch = (($k2 < $len) ? substr($txt,$k2,1) : '');
        if (($ch eq '/')&&($nch eq '*')) {
            $ttxt = substr($txt,($k2+1));
            return $k2, $ptxt, $ttxt;   # return offset, previous and begin comment
        }
        $pch = $ch;
        $ptxt .= $ch;
    }
    return 0, $ptxt, $ttxt;
}

sub inline_comment_starts {
    my ($txt) = shift;
    my $len = length($txt);
    my $ptxt = '';
    my ($k, $ch, $pch, $k2, $nch);
    for ($k = 0; $k < $len; $k++) {
        $k2 = $k + 1;
        $ch = substr($txt,$k,1);
        $nch = (($k2 < $len) ? substr($txt,$k2,1) : '');
        if (($ch eq '/')&&($nch eq '/')) {
            return $k2, $ptxt;   # return offset, previous
        }
        $pch = $ch;
        $ptxt .= $ch;
    }
    return 0, $ptxt;
}

sub C_comment_ends {
    my ($txt) = shift;
    my $len = length($txt);
    my $ttxt = '';
    my ($k, $ch, $pch, $k2, $nch);
    for ($k = 0; $k < $len; $k++) {
        $k2 = $k + 1;
        $ch = substr($txt,$k,1);
        $nch = (($k2 < $len) ? substr($txt,$k2,1) : '');
        if (($ch eq '*')&&($nch eq '/')) {
            $ttxt = substr($txt,($k2+1));
            return $k2, $ttxt;  # return trailing 
        }
        $pch = $ch;
    }
    return 0, $ttxt;
}

sub get_C_file_lines {
    my ($inf) = shift;
    my (@lines, $lncnt, $line, $tline);
    my ($isc, $ptxt, $i, $ttxt, $ise, $atxt, $i2, $ctxt);
    my $incomm = 0;
    my $lnnum = 0;
    my ($typ, $inmacro, $len, $ch, $j, $braces, $pbrac);
    my ($msg);
    my @nlines = ();
    $inmacro = 0;
    $braces = 0;
    $pbrac = 0;
    if (open INF, "<$inf") {
        @lines = <INF>;
        close INF;
        $lncnt = scalar @lines;
        prt( "Processing $lncnt lines, from $inf ...\n") if ($dbg43);
        for ($i = 0; $i < $lncnt; $i++) {
            $lnnum++;
            $line = $lines[$i];
            $tline = trim_all($line);

            if ( $incomm ) {
                ($ise,$atxt) = C_comment_ends($tline);
                if ($ise) {
                    $msg = "$lnnum: Comment ends";
                    $msg .= " [$atxt] follows" if length($atxt);
                    prt( "$msg\n" ) if ($dbg43);
                    $incomm = 0;
                    $tline = trim_all($atxt);
                }
            }
            if ( ! $incomm ) {
                $ctxt = $tline;
                ($isc,$ptxt,$ttxt) = C_comment_starts($tline);
                if ($isc) {
                    # deal with any $ptxt ..
                    ($ise,$atxt) = C_comment_ends($ttxt);
                    if ($ise) {
                        while ($isc && $ise) {
                            $ptxt = trim_all($ptxt);
                            $atxt = trim_all($atxt);
                            $ctxt = $ptxt;
                            $ctxt .= ' ' if (length($ctxt) && length($atxt) && ($atxt ne ';'));
                            $ctxt .= $atxt if length($atxt);
                            $ctxt = trim_all($ctxt);
                            $msg = "$lnnum: Comment starts/ends - ";
                            $msg .= "[$ptxt] before " if length($ptxt);
                            $msg .= "[$atxt] follows " if length($atxt);
                            prt( "$msg\n" ) if ($dbg43);
                            ($isc,$ptxt,$ttxt) = C_comment_starts($ctxt);
                            $atxt = '';
                            if ($isc) {
                                ($ise,$atxt) = C_comment_ends($ttxt);
                            }
                            $ptxt = trim_all($ptxt);
                            $atxt = trim_all($atxt);
                            $ctxt = $ptxt;
                            $ctxt .= ' ' if (length($ctxt) && length($atxt) && ($atxt ne ';'));
                            ###$ctxt .= ' ' if length($ctxt);
                            $ctxt .= $atxt if length($atxt);
                            $ctxt = trim_all($ctxt);
                        }
                    } else {
                        $ctxt = trim_all($ptxt);
                        $msg = "$lnnum: IN Comment";
                        $msg .= " after [$ptxt]" if length($ptxt);
                        prt( "$msg\n" ) if ($dbg43);
                        $incomm = 1;
                    }
                }
                $tline = $ctxt;
                if (! $incomm) {
                    ($isc,$ptxt) = inline_comment_starts($tline);
                    if ($isc) {
                        $ctxt = trim_all($ptxt);
                        $msg = "$lnnum: INLINE Comment";
                        $msg .= " after [$ptxt]" if length($ptxt);
                        prt( "$msg\n" ) if ($dbg43);
                    } else {
                        $ctxt = $tline;
                    }
                }
            }
            $tline = trim_all($ctxt);
            push(@nlines, $tline) if length($tline);
        }
    } else {
        prtw( "WARNING: Unable to OPEN [$inf]!\n" );
    }
    return @nlines;
}

sub get_include_list2($$$) {
    my ($caller, $fil, $rarr) = @_;
    my @lines = get_C_file_lines($fil);
    my $lncnt = scalar @lines;
    my $inc = '';
    prt( "Processing $lncnt lines, from $fil ...\n") if ($dbg44);
    for (my $i = 0; $i < $lncnt; $i++) {
        my $line = $lines[$i];
        if ($line =~ /\s*#\s*include\s+(.+)/ ) {
            $inc = $1;
            push(@{$rarr},$inc);
            prt( "include: [$inc] ($line)\n" ) if ($dbg44);
        }
    }
}

sub get_include_list {
    my ($caller, $sf, $fil, $rarr) = @_;
    if ( -f $fil ) {
        get_include_list2($caller, $fil,$rarr);
    } elsif (-f $sf) {
        get_include_list2($caller, $sf,$rarr);
    } else {
        prtw( "WARNING:caller:$caller: Unable to find [$fil] or sf=[$sf]\n" );
    }
}

sub show_inc_hash {
    my ($key, $val, $cnt);
    $cnt = scalar keys(%inc_hash);
    prt( "\nShow of $cnt keys in inc_hash ...\n" );
    foreach $key (sort keys %inc_hash) {
        $val = $inc_hash{$key};
        prt( "$key = [$val]\n" );
    }
    prt("Done\n");
}

sub process_input_files() {
    if (@input_files) {
        @inf = @input_files;
        prt( "Processing ".scalar @inf." files...\n" );
        foreach my $fil (@inf) {
            if (!does_next_am_file_exist($fil)) {
                my $msg = "\nERROR: Can NOT proceed. No such makefile [$fil]!";
                $msg .= "\n       That is, can NOT find an .am file of this name!";
                $msg .= "\n       Nor an .in file of this name." if ($support_makefile_in);
                $msg .= "\n       This file was indicated during the scanning of 'configure.ac'!\n";
                pgm_exit(1,"$msg\n");
            }
        }
        foreach my $fil (@inf) {
            process_one_file($fil);
        }
    }
}

sub process_other_files() {
    @other_inputs = get_missed_makes($main_root_dir);
    my ($fil_name, $fil_dir, $am_file, $mk);
    if (@other_inputs) {
        prt( "Other AM files, not used = ".scalar @other_inputs." ...\n" );
        foreach my $afile (@other_inputs) {
            ($fil_name, $fil_dir) = fileparse($afile);
            ##$full_fil_path = unix_2_dos($main_root_dir . $fil_dir);
            $full_fil_path = loc_fix_rel($main_root_dir . $fil_dir);    # also returns DOS, minus trailing '\'
            $full_fil_path .= "\\" if ( !($full_fil_path =~ /\\$/) );    # add trailing '\' IF
            # 2010-08-26 - This does NOT account for Makefile.in!!! Soooo
            # but ONLY if $support_makefile_in is ON (-m)
            #$next_am_file = $afile;
            #$next_am_file .= ".am" if (has_no_extent($afile) && !is_am_file($afile));
            if (!does_next_am_file_exist($afile)) {
                prtw("WARNING: Skipping no existing [$afile]+extension. ".
                    ($support_makefile_in ? "NO am or in" : "Maybe with -m")."\n");
                next;
            }
            $next_am_file = get_next_am_file($afile,"process_other_files");
            prt( "Processing other [$next_am_file] in ($full_fil_path) ...\n" );
            process_am_file('Others', $afile, $main_root_dir) if !exclude_dir($afile);
            #my $mk = mark_all_files(unix_2_dos($main_root_dir . $afile ));
            $am_file = get_next_full_am_file($afile);
            $mk = mark_all_files($am_file);
            prtw( "WARNING:O: NOT FOUND IN MARK [$am_file]!\n" ) if (!$mk);
        }
    }
}

sub write_upd_bat($$) {
    my ($ra,$out) = @_; # \@copy_bat,$temp_upd_bat
    my $cnt = scalar @{$ra};
    return if (!$cnt);
    my ($msg,$i,$tmp,$fin);
    $msg = "\@echo WARNING: This will overwrite any EXISTING DSP/DSW files in [$target_dir]!\n";
    $msg .= "\@echo *** ARE YOU SURE YOU WANT TO CONTINUE? *** Ctrl+C to abort...\n";
    $msg .= "\@pause\n";
    $msg .= "\@echo *** LAST CHANCE! *** Ctlr+C to abort.\n";
    $msg .= "\@pause\n";
    for ($i = 0; $i < $cnt; $i++) {
        $tmp = ${$ra}[$i][0];
        $fin = ${$ra}[$i][1];
        $msg .= "copy $tmp $fin\n";
    }
    $msg .= "\@echo Copied $cnt files... All done...\n";
    write2file($msg,$out);
    $msg = "NOTICE: Have written an UPDATE batch file to [$out]...\n";
    $final_message = $msg;
    prtw($msg);
}

#########################################################
### MAIN ###
# set_dbg_rel2(1);
set_all_dbg_off();

parse_args(@ARGV);

get_top_files( $main_root_dir, 0 );

scan_root_folder( $main_root_dir );

process_input_files();  # 'AC_OUTPUT(...)' 'Makefile.am (or .in) from configure.ac (or .in)

### pgm_exit(1,"REVIEW");

process_other_files();  # 'AC_OUTPUT(...)' Other than 'Makefile.am (or .in) from configure.ac (or .in)

$c_cnt = scalar @msvc_c_files;
$t_cnt = scalar @msvc_titles;
$h_cnt = scalar @msvc_h_files;
$o_cnt = scalar keys(%other_projs);
prt( "c_cnt = $c_cnt, h_cnt = $h_cnt, t_cnt = $t_cnt, o_cnt = $o_cnt ...\n" );

extract_am_projects();

$p_cnt = scalar keys(%am_projects);

prt( "Moment, generating inc_hash ... from $p_cnt AM projects ...\n" );
gen_inc_hash_am( $main_root_dir );
gen_inc_hash_others( $main_root_dir );
### show_inc_hash();
prt( "Done generating inc_hash ...\n" );

show_am_projects( $main_root_dir );
show_other_projects( $main_root_dir );

show_source_list( "makefile.am set", $main_root_dir ) if ($show_all_sources || $show_missed_sources);

gen_temp_dsw( $main_root_dir );

if ($write_temp_ds && @copy_bat && length($temp_upd_bat) && !$only_dry_run) {
    write_upd_bat(\@copy_bat,$temp_upd_bat);
}

pgm_exit($exit_status,"");

### END MAIN ###
########################################
sub give_help {
    my ($tmp);
    prt("$pgmname: version 0.3.1 2010-09-22\n");
    prt(" Suspended this script in favour of amsrcs04.pl with fuller implementation.\n");
    prt("Usage: $pgmname [options] [input-directory]\n");
    prt("Options:\n");
    prt(" --help   (-h or -?) = This help, and exit 0.\n");
    prt(" --flags <flag> (-f) = Add to defines flag/macro. '-f FOO', to add '/D \"FOO\"' to the compile.\n");
    $tmp = get_dbg_range();
    prt(" --dbg <num>    (-d) = Set DEBUG flag of this value. Number in range 1 to $tmp\n");
    prt(" --incs <path>  (-i) = Add to includes. '-i .', to add '/I \".\"' tot he compile.\n");
    prt(" --load_log     (-l) = Load log at end, using default 'txt' editor.\n");
    prt(" --make_in      (-m) = Add support for Makefile.in parsing, but this is not complete.\n");
    prt(" --out <opt>    (-o) = Output list of sources, indicating if 'main' found. opt='all' or 'missed'\n");
#    prt(" --proj <name> (-p)  = Set project name'.\n");
    prt(" --resp <file>  (-r) = Commands from a reponse/input file.\n");
    prt(" --src <dir>    (-s) = Source directory to scan.\n");
    prt(" --targ <dir>   (-t) = Target directory for DSP file.\n");
    prt("PURPOSE:\n");
    prt(" Scan the target directory for 'configure.ac', and process for valid 'projects',\n");
    prt(" and write a temp.proj_name.DSP file for each project found.\n");
    prt("NOTES:\n");
    prt(" If no input directory is given, then the current directory will be used.\n");
    prt(" If no target directory given, then the input directory will be used, and each DSP\n");
    prt("  will be relative to this target directory.\n");
    prt(" The input file is a set of line delimited commands. Lines beginning with '#' are skipped.\n");
    prt("\n");
    prt(" The debug switch is strictly for that. It adds no functionality, just a noisier output,\n");
    prt("  and has the text settings of 'all', 'none', or 'help', to show the list in more detail.\n");
    prt("  And there is another, namely 'dry-run', to do all the scanning, but do NOT write DSW/DSP file.\n");
    $tmp = get_dbg_stg();
    prt(" For debug, presently values [$tmp] are ON\n") if (length($tmp));
    prt(" For debug, the pre-processed Makefile.in will be written to [$temp_in_file]\n") if (length($temp_in_file));
    prt(" For debug, the adjusted IN_MACS will be written to [$temp_in_macs].\n") if (length($temp_in_macs));
}
sub need_arg {
    my ($arg,@av) = @_;
    pgm_exit(1,"ERROR: [$arg] must have following argument!\n") if (!@av);
}

sub show_dbg_help() {
    my $file = $0;
    my ($line,$max,$tmp,$cnt);
    $max = get_dbg_range();
    $tmp = get_dbg_stg();
    prt(" --dbg <num>  (-d)  = Set DEBUG flag of this value. Number in range 1 to $tmp\n");
    prt(" Presently %tmp are ON.\n") if (length($tmp));
    prt(" Additional text setting are 'all', 'none', and this 'help'.\n");
    if (open INF, "<$file") {
        my @lines = <INF>;
        close INF;
        prt(" Detailed list, with some 'notes' indicating what each does.\n");
        $cnt = 0;
        foreach $line (@lines) {
            $line = trim_all($line);
            if ($line =~ /^my\s+\$dbg(\d+)\s*=\s*\d+\s*;\s*(.+)$/) {
                $tmp = $1;
                prt("$tmp: $line\n");
                $cnt++;
            }
        }
        prt("ERROR: Found no \$dbg??vars in open file [$file], so NO DEBUG ADDITIONAL HELP!\n") if (!$cnt);
    } else {
        prt("ERROR: Unable to open file [$file], so NO DEBUG ADDITIONAL HELP!\n");
    }
}

sub set_cmd_line {
    my (@av) = @_;
    my ($arg);
    foreach $arg (@av) {
        $cmd_line .= " " if (length($cmd_line));
        $cmd_line .= $arg;
    }
}

my $in_load_input = 0;
sub load_input_file($$) {
    my ($arg,$file) = @_;
    if (open INF, "<$file") {
        my @lines = <INF>;
        close INF;
        my @carr = ();
        my ($line,@arr);
        foreach $line (@lines) {
            $line = trim_all($line);
            next if (length($line) == 0);
            next if ($line =~ /^#/);
            @arr = split(/\s/,$line);
            push(@carr,@arr);
        }
        $in_load_input = 1;
        parse_args(@carr);
        $in_load_input = 0;
    } else {
        pgm_exit(1,"ERROR: Unable to 'open' file [$file]!\n")
    }
}

sub add_to_defines($$) {
    my ($arg,$def) = @_;
    my $add = "/D \"$def\"";
    $msvc_cflags .= ' ' if (length($msvc_cflags));
    $msvc_cflags .= $add;
    prt("With $arg, added [$add]\n");
}

sub add_to_includes($$) {
    my ($arg,$def) = @_;
    my $add = "/I \"$def\"";
    $msvc_cflags .= ' ' if (length($msvc_cflags));
    $msvc_cflags .= "/I \"$def\"";
    prt("With $arg, added [$add]\n");
}

sub parse_args {
    my (@av) = @_;
    my ($arg,$sarg,$tmp);
    set_cmd_line(@av);
    while (@av) {
        $arg = $av[0];
        if ($arg =~ /^-/) {
            $sarg = substr($arg,1);
            $sarg = substr($sarg,1) while ($sarg =~ /^-/);
            if (($sarg =~ /^h/i)||($sarg eq '?')) {
                give_help();
                pgm_exit(0,"Help exit(0)");
            } elsif ($sarg =~ /^f/i) {  # flags (defines)
                need_arg(@av);
                shift @av;
                $sarg = $av[0];
                add_to_defines($arg,$sarg);
            } elsif ($sarg =~ /^i/i) {  # includes
                need_arg(@av);
                shift @av;
                $sarg = $av[0];
                add_to_includes($arg,$sarg);
            } elsif ($sarg =~ /^r/i) {  # response file
                need_arg(@av);
                shift @av;
                $sarg = $av[0];
                load_input_file($arg,$sarg);
            } elsif ($sarg =~ /^m/i) {
                $support_makefile_in = 1;
                prt("Adding Makefile.in support, but not completed!\n");
            } elsif ($sarg =~ /^t/i) {
                need_arg(@av);
                shift @av;
                $sarg = $av[0];
                $target_dir = File::Spec->rel2abs($sarg);
                prt("Set target directory to [$target_dir]\n");
                pgm_exit(1,"ERROR: Target DIRECTORY does NOT EXIST!\n") if (! -d $target_dir);
            } elsif ($sarg =~ /^o/i) {
                need_arg(@av);
                shift @av;
                $sarg = $av[0];
                if ($sarg =~ /^all$/i) {
                    $show_all_sources = 1;
                } elsif ($sarg =~ /^missed$/i) {
                    $show_missed_sources = 1;
                } else {
                    pgm_exit(1,"ERROR: Invalid argument [$arg $sarg]! Only 'all' or 'missed' allowed!\n");
                }
            } elsif ($sarg =~ /^s/i) {
                need_arg(@av);
                shift @av;
                $sarg = $av[0];
                $main_root_dir = File::Spec->rel2abs($sarg);
                prt("Set input to [$main_root_dir]\n");
            } elsif ($sarg =~ /^d/i) {
                need_arg(@av);
                shift @av;
                $sarg = $av[0];
                $tmp = get_dbg_range();
                if (($sarg =~ /^\d+$/)&&($sarg >= 1)&&($sarg <= $tmp)) {
                    $tmp = 'dbg';
                    if ($sarg < 10) {
                        $tmp .= "0$sarg";
                    } else {
                        $tmp .= "$sarg";
                    }
                    set_dbg_var($sarg);
                    prt("Set Debug $tmp ON!\n");
                } else {
                    if ($sarg =~ /^\d+$/) {
                        pgm_exit(1,"ERROR: Invalid argument [$arg $sarg]! Out of range 1 - $tmp\n");
                    } else {
                        if ($sarg =~ /^help$/i) {
                            show_dbg_help();
                            pgm_exit(0,"DEBUG Help exit(0)\n");
                        } elsif ($sarg =~ /^all$/i) {
                            prt("Setting ALL debug ON!\n");
                            set_all_dbg_on();
                        } elsif ($sarg =~ /^none$/i) {
                            prt("Setting ALL debug OFF!\n");
                            set_all_dbg_off();
                        } elsif ($sarg =~ /^dry-run$/i) {
                            prt("Setting DRY RUN ONLY!\n");
                            $only_dry_run = 1;
                            $out_dsp = 0;
                            $out_dsp2 = 0;
                        } else {
                            pgm_exit(1,"ERROR: Invalid argument [$arg $sarg]! Not numerical in range 1 - $tmp, nor 'all', 'none', 'help' or 'dry-run'!\n");
                        }
                    }
                }
            } elsif ($sarg =~ /^l/i) {
                prt("Setting Load log at end.\n");
                $load_log = 1;
            } else {
                pgm_exit(1,"ERROR: Invalid argument [$arg]! Try -?\n");
            }
        } else {
            $main_root_dir = File::Spec->rel2abs($arg);
            prt("Set input to [$main_root_dir]\n");
        }
        shift @av;
    }

    return if ($in_load_input);

    if ((length($main_root_dir) ==  0) && $debug_on) {
        $main_root_dir = $def_in_dir;
        set_all_dbg_on();
    }

    if (length($main_root_dir) ==  0) {
        if ($use_current_dir) {
            $main_root_dir = path_u2d($cwd);
            prt("Setting input to CURRENT [$main_root_dir]\n");
        } else {
            pgm_exit(1,"ERROR: No input root directory found in command!\n");
        }
    }

    $main_root_dir .= "\\" if ( !($main_root_dir =~ /(\\|\/)$/) );
    if (length($target_dir) == 0) {
        $target_dir = $main_root_dir;
        prt("Set target directory to [$target_dir], based on main ROOT directory.\n");
    }

    pgm_exit(1,"ERROR: Root [$main_root_dir] does NOT continain a 'configure.ac' file!\n") if (!test_root_folder($main_root_dir));

}

# eof - amsrcs03.pl
