#!/Perl
# 
use strict;
use Cwd;

my $VERSION = "0.5";
my $PACKAGE = "am2dsp5";
# String 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]+)\$";
my $MACRO_PATTERN = "^([A-Za-z][A-Za-z0-9_]*)[ \t]*([:+]?)=[ \t]*(.*)\$";
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]*([^)]+)";

# Hash table of AM_CONDITIONAL variables seen in configure.
my %configure_cond = ();
# This holds the names which are targets.  These also appear in
# %contents.
my %targets = ();
# This holds the line numbers at which various elements of
# %contents are defined.
my %content_lines = ();
my %content_seen = ();
# This maps the source extension of a suffix rule to its
# corresponding output extension.
my %suffix_rules = ();
# Hash table of discovered configure substitutions.  Keys are names,
# values are `FILE:LINE' strings which are used by error message
# generation.
my %configure_vars = ();
# This holds the set of included files.
my @include_stack = ();
my $verbose = 0;
my $vcond;
my @conditional_stack = ();
my %contents = ();
my %conditional = ();
# This holds our (eventual) exit status.  We don't actually exit until
# we have processed all input files - except when 'critical' ...
my $exit_status = 0;
my @make_input_list = ();
my %make_list = ();
# Names used in AC_CONFIG_HEADER call.  @config_fullnames holds the
# name which appears in AC_CONFIG_HEADER, colon and all.
# @config_names holds the file names.  @config_headers holds the '.in'
# files.  Ordinarily these are similar, but they can be different if
# the weird "NAME:FILE" syntax is used.
my @config_fullnames = ();
my @config_names = ();
my @config_headers = ();
# Line number at which AC_CONFIG_HEADER appears in configure.ac.
my $config_header_line = 0;
# Relative location of top build directory.
my $top_builddir = '';
my $relative_dir = '.';
my $output_vars = '';
my $output_trailer = '';
# List of Makefile.am's to process, and their corresponding outputs.
my @input_files = ();
my %output_files = ();
# List of files in AC_OUTPUT without Makefile.am, and their outputs.
my @other_input_files = ();
my @var_list = ();
my %am_vars = ();
my %def_type = ();
my @excluded_dirs = ();
my @excluded_files = ();
my $msvc_cflags = "";
my $msvc_threads = "";
my $msvc_libs = "";
my @extra_sources = ();
my @extra_projects = ();
my %used_inc_paths = ();
my %used_lib_paths = ();

# new variables
my $verbose2 = 0;
my $verbose3 = 1;
my $msvc_dlibs = "";
my $msvc_rlibs = "";
my $in_debug = 0;
my $in_release = 0;
my $do_check = 0;
my $def_cfg = "am2dsp5.cfg";
my $src_cfg = $def_cfg;
my $root_dir = '';
my @msvc_dlibs_list = ();
my @msvc_rlibs_list = ();
my @msvc_libs_list = ();
my @msvc_dlibs_paths = ();
my @msvc_rlibs_paths = ();
my @msvc_libs_paths = ();
my @msvc_inc_paths = ();
my @test_headers = ( 'zlib.h', 'AL/al.h', 'AL/alut.h',
  'simgear/compiler.h', 'simgear/debug/logstream.hxx', 'plib/pu.h', 'Main/main.hxx',
  'config.h', 'include/general.hxx', 'FGJSBBase.h');
my $add_groups = 0; # default to single, put duplicates 'Dupes' folder ... 
my @msvc_c_files = ();
my @msvc_h_files = ();
my @msvc_titles = (); # just to deal with duplicate names
# EXTRA_DIST file lists from Makefile.am list
my @msvc_c_extra = ();
my @msvc_h_extra = ();
my @msvc_o_extra = ();
my $err_msg = '';
# am2dsp?.cfg define = AAA
my %cfg_defines = ();
# configure.ac equivalent
my %def_defines = ( 'FG_JPEG_SERVER', 'ENABLE_JPEG_SERVER' );

# Extracted from AM_INIT_AUTOMAKE(package,version)
my $dsp_package = 'FGFS';
my $dsp_version = '0.2';

my $static_lib = 0;
my $write_old_dsp = 0;
my $write_log = 1;

# msvc8 stuff
my $mod_vcproj = 0;
my $debug_on = 0;
my $debug_on2 = 0;
my $debug_on3 = 0;
my $debug_on4 = 0;
my $debug_on5 = 0;
my $vc8_root = 'projects\\VC8\\';
my $vc8_def_lib = $vc8_root.'FlightGearLib.vcproj';
my $vc8_def_main = $vc8_root.'FlightGear.vcproj';
my $add_vc8_path = '..\\..\\'; # relative from vcproj to DSW/DSP

# VC8 project files and lines
my $vc8_src_lib = $root_dir . $vc8_def_lib;
my $vc8_src_main = $root_dir . $vc8_def_main;
my @vc8_lib_lines = (); # storage of RAW lines
my @vc8_main_lines = ();
# VC8 information extracted from lines ...
# VC8 headers and sources
##############################################
my @vc8_main_hdrs = ();
my @vc8_main_srcs = ();
my @vc8_lib_hdrs = ();
my @vc8_lib_srcs = ();
my @vc8_dup_hdrs = ();
my @vc8_dup_srcs = ();
# VC8 include path, libraries and library paths
###############################################
# MAIN storeage
# configuration stuff
my %main_msvc8_confi = ();
my $main_msvc8_dintd = '';
my $main_msvc8_rintd = '';
# compiler stuff
my @main_msvc8_dincs = ();
my @main_msvc8_ddefs = ();
my @main_msvc8_rincs = ();
my @main_msvc8_rdefs = ();
# linker stuff
my @main_msvc8_dlibs = ();
my @main_msvc8_dpath = ();
my @main_msvc8_rlibs = ();
my @main_msvc8_rpath = ();
# other items
my $main_warn = '';
# LIBRARY storage
# configuration stuff
my %lib_msvc8_confi = ();
my $lib_msvc8_dintd = '';
my $lib_msvc8_rintd = '';
# compiler stuff
my @lib_msvc8_dincs = ();
my @lib_msvc8_ddefs = ();
my @lib_msvc8_rincs = ();
my @lib_msvc8_rdefs = ();
# linker stuff
my @lib_msvc8_dlibs = ();
my @lib_msvc8_dpath = ();
my @lib_msvc8_rlibs = ();
my @lib_msvc8_rpath = ();
# other items
my $lib_warn = '';
my @not_in_vc8 = ();
my @not_in_am = ();
my %am_to_vc8 = ();
# storeage of lines to DELETE
my @vc8_main_delete = ();
my @vc8_lib_delete = ();
###############################################


# temporary collector variables
# configuration stuff
my %msvc8_confi = ();
my $msvc8_dintd = '';
my $msvc8_rintd = '';
# compiler stuff
my @msvc8_dincs = ();
my @msvc8_ddefs = ();
my @msvc8_rincs = ();
my @msvc8_rdefs = ();
# linker stuff
my @msvc8_dlibs = ();
my @msvc8_dpath = ();
my @msvc8_rlibs = ();
my @msvc8_rpath = ();
# other items
my $warn = '';

my ($LOG);
my $outfile = 'templog5.txt';
if ( open $LOG, ">$outfile" ) {
    $write_log = 1;
} else {
    $write_log = 0;
    prt( "WARNING: Unable to open $outfile LOG ...\n" );
}
my $cwdir = getcwd();

parse_arguments(@ARGV);

# Read project configuration file.
read_am2dsprc($src_cfg);

scan_configure();

mydie( "$PACKAGE: no input_files, so no 'Makefile.am' found or specified\n" )
    if ! @input_files;

if ($write_old_dsp) {
    if ($static_lib) {
        static_lib_dsp_init($dsp_package);
    } else {
        console_app_dsp_init($dsp_package);
    }
}

my $am_file;
if ( ! $add_groups && $write_old_dsp ) {
    add_group_start($dsp_package);
}

foreach $am_file (@input_files) {
    prt( "\nProcessing [$am_file] from input_files array ...\n" ) if $verbose2;
    dsp_add_group($dsp_package, $am_file) if !exclude_dir($am_file);
}
if ( ! $add_groups && $write_old_dsp ) {
    add_group_end($dsp_package);
}

if ($write_old_dsp) {
    dsp_finish($dsp_package);
    generate_dsw( $dsp_package );
    prt( "Done ".$root_dir.$dsp_package." DSP and DSW files ...\n" );
}

if ($do_check) {
    check_includes();
}

if ( ! $write_old_dsp) {
    write_new_dsp(); # experimental NEW DSP separating source and headers
}
if ( $mod_vcproj ) {
    amend_vcproj();    # experimental - amend the VCPROJ files
}

exit $exit_status;
# end of process

sub add_group_start {
    my $dsp_name = shift;
    my $dsp_file = $root_dir . $dsp_name . '.dsp';
    open(DSP, ">>$dsp_file") || mydie( "Can't append to $dsp_file: $!\n" );
    print DSP "# Begin Group \"Source Files\"\r\n";
    print DSP "\r\n";
    print DSP "# PROP Default_Filter \"cpp;c;cxx;rc;def;r;odl;idl;hpj;bat;h;hpp;hxx;hm;inl\"\r\n";
    close(DSP);
}

sub add_group_end {
    my $dsp_name = shift;
    my $dsp_file = $root_dir . $dsp_name . '.dsp';
    open(DSP, ">>$dsp_file") || mydie( "Can't append to $dsp_file: $!\n" );
    print DSP "# End Group\r\n";
    close(DSP);
}


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

sub exclude_file {
    my $file = shift;
    foreach my $f (@excluded_files) {
    if ($file =~ /$f/) {
        return 1;
    }
    }
    return 0;
}

#
# TODO: option to specify static library or console app.
#
sub give_little_help {
    prt( "am2dsp5: Just a little help ...\n" );
    prt( "--help (or -h, -?) - This brief help!\n" );
    prt( "--verbose (or -v)  - Sets verbose mode. (-v2 for MORE)\n" );
    prt( "--package name     - Set the DSP package name (default = $dsp_package)\n" );
    prt( "--lib (or -l)      - To create static library (Default is console app.)\n" );
    prt( "--groups (or -g)   - Output source into 'group' folders, as original!\n" );
    prt( "--dir path         - Establish input path for source, and the $def_cfg.\n" );
    prt( "--check (or -c)    - Check libraries, and some known include files, and exit.\n" );
    prt( "--cfg path\\file   - Use a specific configuration file, if not with source.\n" );
    prt( "--msvc8            - Modify, or check, the vcproj files, if found.\n" );
    prt( "Note, this --cfg path\\file MUST be after the --dir path, if used.\n" );
    prt( "Any other option beginning with '-' will abort, with a complaint ...\n" );
    mydie( "Any other input    - is ignored ...\n" );
}

sub set_input_dir {
    my $cfg = shift;
    if ( !(($cfg =~ /\/$/) || ($cfg =~ /\\$/)) ) {
        $cfg .= '\\';
    }
    my $fil = $cfg . $def_cfg;
    $src_cfg = $fil;
    $root_dir = $cfg;
    $vc8_src_lib = $root_dir . $vc8_def_lib;
    $vc8_src_main = $root_dir . $vc8_def_main;
    prt( "Using root path [$root_dir] ...\n" );
}

sub parse_arguments {
    my @av = @_;
    my $arg = '';
    while (@av) {
        $arg = $av[0];
        if ($arg eq '--help' || $arg eq '-h' || $arg eq '-?') {
            give_little_help(); # show help and exit
        } elsif ($arg eq '--verbose' || $arg eq '-v') {
            $verbose = 1;
        } elsif ($arg eq '--package' || $arg eq '-p') {
            require_argument(@av);
            shift @av;
            $dsp_package = $av[0];
        } elsif ($arg eq '--lib' || $arg eq '-l') {
            # Create a static library
            $static_lib = 1;
        } elsif ($arg eq '--dir') {
            require_argument(@av);
            shift @av;
            set_input_dir($av[0]);
        } elsif ($arg eq '--check' || $arg eq '-c') {
            $do_check = 1; # perform check and exit
        } elsif ($arg eq '--cfg') {
            require_argument(@av);
            shift @av;
            $src_cfg = $av[0];
        } elsif ($arg eq '-v2' ) {
            $verbose2 = 1;
        } elsif ($arg eq '-v3' ) {
            $verbose3 = 1;
        } elsif ($arg eq '-dbg' ) {
            $verbose = 1;
            $verbose2 = 1;
            $verbose3 = 1;
            $debug_on = 1;
            $debug_on2 = 1;
            $debug_on3 = 1;
        } elsif ($arg eq '--groups' || $arg eq '-g') {
            $add_groups = 1; # use original 'group' folders ... 
        } elsif ($arg eq '--msvc8') {
            $mod_vcproj = 1;
        } elsif ($arg =~ /^-/) {
            mydie( "am2dsp5: unrecognised option, namely '$arg'\nTry --help or -? for some information.\n" );
        } else {
            # quietly IGNORE other inputs???
        }
        shift @av;
    }
    if ( !( -f $src_cfg) ) {
        if ( -f $def_cfg) {
            prt( "Warning: Unable to locate file [$src_cfg] ...\n" );
            prt( "Using file [$def_cfg], in [".getcwd()."], in its place ...\n" );
            $src_cfg = $def_cfg;
        } else {
            mydie("ERROR: Unable to locate file [$src_cfg] ... \ncheck input, and/or folder ... aborting ...\n");
        }
    }
}

sub add_2_msvc {
    my $flg = shift;
    if ($in_debug) {
        $msvc_dlibs .= $flg;
    } elsif ($in_release) {
        $msvc_rlibs .= $flg;
    } else {
        $msvc_libs .= $flg;
    }
}

sub add_2_libs {
    my $flg = shift;
    if ($in_debug) {
        push(@msvc_dlibs_list, $flg);
    } elsif ($in_release) {
        push(@msvc_rlibs_list, $flg);
    } else {
        push(@msvc_libs_list, $flg);
    }
}

sub add_2_libpaths {
    my $flg = shift;
    if ($in_debug) {
        push(@msvc_dlibs_paths, $flg);
    } elsif ($in_release) {
        push(@msvc_rlibs_paths, $flg);
    } else {
        push(@msvc_libs_paths, $flg);
    }
}

sub read_am2dsprc {
    my $rc_file = shift;

    open( RC_FILE, $rc_file )
    or mydie( "Can't open $rc_file: $!\n" );
    my $line;
    my @cond_stack = ();
    while (defined($line = <RC_FILE>)) {
        chomp $line;
        if ($line =~ s/\\$//) {
            # continuation line
            $line .= "%";
            $line .= <RC_FILE>;
            redo unless eof(RC_FILE);
        }

        prt( "Processing line [$line] ...\n" ) if ($debug_on3);
        next if $line =~ /^$/; # ignore blank lines
        next if $line =~ /^#/; # ignore comments

        if ($line =~ /exclude_dir\s*=\s*(\S+)/) {
            push( @excluded_dirs, $1 );
        }
        elsif ($line =~ /exclude_file\s*=\s*(\S+)/) {
            my $f;
            ($f = $1) =~ s/\\/\\\\/g; # escape path separators, "\" -> "\\"
            push( @excluded_files, $f );
            prt( "Excluding file: $f\n" ) if $verbose;
        }
        elsif ($line =~ /include_path\s*=\s*(\S+)/) {
            $msvc_cflags .= " /I \"$1\"";
            push(@msvc_inc_paths, $1);
        }
        elsif ($line =~ /add_vc8_path\s*=\s*(\S+)/) {
            $add_vc8_path = $1;
            prt( "Got from VC8 to root path: [$1]\n" ) if $verbose;
        }
        elsif ($line =~ /define\s*=\s*(\S+)/) {
            if ($debug_on) {
                if (defined $def_defines{$1} ) {
                    prt( "Got define of $1 ... which is $def_defines{$1} ...\n" );
                    $cfg_defines{$def_defines{$1}} = 1; # add configure.ac 
                } else {
                    prt( "Got define of $1 ...\n" );
                }
                if ( defined $cfg_defines{$1} ) {
                    prt( "Warning: cfg_defines of $1 already defined ...\n" );
                }
            }
            $cfg_defines{$1} = 1;
            $msvc_cflags .= " /D \"$1\"";
        }
        elsif ($line =~ /lib_path\s*=\s*(\S+)/) {
            add_2_msvc( " /libpath:\"$1\"" );
            add_2_libpaths( "$1" );
        }
        elsif ($line =~ /add_lib\s*=\s*(\S+)/) {
            add_2_msvc( " $1.lib" );
            add_2_libs( "$1.lib" );
        }
        elsif ($line =~ /type\s*=\s*(\S+)/) {
            my ($type,$threads,$debug) = split /,/, $1;
            prt( "type=$type, threading=$threads, debug=$debug\n" ) if $verbose;
            if ($type =~ "ConsoleApplication") {
            $static_lib = 0
            }
            elsif ($type =~ "StaticLibrary") {
            $static_lib = 1
            }
            else {
            # Invalid type
            }

            my $flags = " /ML"; # single threaded.
            if ($threads =~ /Multithreaded/) {
            $flags = " /MT";
            }
            elsif ($threads =~ /Singlethreaded/) {
            $flags = " /ML";
            }
            else {
            # Invalid threading option.
            }

            if ($debug =~ /Debug/) {
            $flags .= "d";
            }

            $msvc_cflags .= $flags;
        }
        elsif ($line =~ /add_source_file\s*=\s*(.*)/) {
            my $rule;
            ($rule = $1) =~ s/%/\r\n/g;
            push( @extra_sources, $rule );
        }
        elsif ($line =~ /add_project\s*=\s*(.*)/) {
            push( @extra_projects, $1 );
        }
        elsif ($line =~ /$IF_PATTERN/o) {
            my $ifcond = $1;
            if ($ifcond =~ /Debug/io) {
                prt( "Entering DEBUG ...\n" ) if $verbose2;
                $in_debug = 1;
                $in_release = 0;
            } elsif ($ifcond =~ /Release/io) {
                prt( "Entering RELEASE ...\n" ) if $verbose2;
                $in_release = 1;
                $in_debug = 0;
            } else {
                prt( "EEK! Got $ifcond ...\n" );
                mydie( "Presently ONLY if switch is 'Debug' or 'Release'!\n" );
            }
            push (@cond_stack, "\@" . $ifcond . "_TRUE\@");
        }
        elsif ($line =~ /$ELSE_PATTERN/o) {
            if (! @cond_stack) {
                mydie( "else without if!\n" );
            }
            elsif ($cond_stack[$#cond_stack] =~ /_FALSE\@$/) {
                mydie( "else after an else!\n" );
            } else {
                if ($in_debug) {
                    prt( "Switch to RELEASE ...\n" ) if $verbose2;
                    $in_debug = 0;
                    $in_release = 1;
                } else {
                    prt( "Switch to DEBUG ...\n" ) if $verbose2;
                    $in_debug = 1;
                    $in_release = 0;
                }
                $cond_stack[$#cond_stack] =~ s/_TRUE\@$/_FALSE\@/;
            }
        }
        elsif ($line =~ /$ENDIF_PATTERN/o) {
            if (! @cond_stack) {
                mydie( "endif without if!\n" );
            }
            prt( "Exit $cond_stack[$#cond_stack] ...\n" ) if $verbose2;
            pop (@cond_stack);
            $in_debug = 0;
            $in_release = 0;
        }

    } # end while


    close(RC_FILE);
}

# Ensure argument exists, or die.
sub require_argument
{
    my ($arg, @arglist) = @_;
    mydie( "$PACKAGE: no argument given for option '$arg'\n" ) if ! @arglist;
}

sub scan_configure {
    my $ff = $root_dir . 'configure.ac';
    scan_one_configure_file($ff);
    $ff = $root_dir . 'aclocal.m4';
    scan_one_configure_file($ff)
    if -f $ff;

    if (! @input_files) {
        prt( "Copying " . scalar @make_input_list . " make_input_list to input_files.\n" ) if $verbose2;
        @input_files = @make_input_list;
        %output_files = %make_list;
    } else {
        prt( "input_files has list of " . scalar @input_files . " ...\n" ) if $verbose2;
    }
    if ($verbose2) {
        foreach $ff (@input_files) {
            prt( "$ff\n" );
        }
    }
}

sub scan_one_configure_file {
    my $filename = shift;
    open(CONFIGURE, $filename)
    || mydie( "$PACKAGE: can't open '$filename': $!\nCurrently running in $cwdir ...\n" );

    prt( "$PACKAGE: reading $filename\n" ) if $verbose;

    my $in_ac_output = 0;
    my $ac_output_line = '';
    my $ff = '';
    while (<CONFIGURE>) {
    # Remove comments from current line.
    s/\bdnl\b.*$//;
    s/\#.*$//;

        # Skip macro definitions.  Otherwise we might be confused into
        # thinking that a macro that was only defined was actually
        # used.
        next if /AC_DEFUN/;

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

    if (! $in_ac_output && ( s/AC_OUTPUT\s*\(\[?// || s/AC_CONFIG_FILES\s*\(\[?// ) ) {
        $in_ac_output = 1;
        $ac_output_line = $.;
    }

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

        # Look at potential Makefile.am's
        foreach (split)
        {
            # Must skip empty string for Perl 4.
            next if $_ eq "\\" || $_ eq '';

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

        # Handle configuration headers.  A config header of `[$1]'
        # means we are actually scanning AM_CONFIG_HEADER from
        # aclocal.m4.
        if (/A([CM])_CONFIG_HEADER\s*\((.*)\)/
            && $2 ne '[$1]')
        {
            &am_conf_line_error
                ($filename, $., "\`automake requires \`AM_CONFIG_HEADER', not \`AC_CONFIG_HEADER'")
                    if $1 eq 'C';

            $config_header_line = $.;
            my ($one_hdr);
            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 (/$AM_CONDITIONAL_PATTERN/o)
    {
        if ( defined $cfg_defines{$1} ) {
            # has been DEFINED in am2dsp?.cfg file
            prt( "Storing configure_cond key $1 ... value=2\n" ) if ($debug_on3);
            $configure_cond{$1} = 2;
        } else {
            prt( "Storing configure_cond key $1 ... value=1\n" ) if ($debug_on3);
            $configure_cond{$1} = 1;
        }
    }

    if (/$AM_INIT_AUTOMAKE/o)
    {
        $dsp_package = $1;
        $dsp_version = $2;
    }
    }

    close(CONFIGURE);
}

sub read_main_am_file {
    $am_file = shift;

    read_am_file($am_file);

    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 read_am_file {
    $am_file = shift;
    open( AM_FILE, $am_file )
    or mydie( "Can't open $am_file: $!\n" );

    prt( "$PACKAGE: reading $am_file\n" ) if $verbose;

    my $saw_bk = 0;
    my $was_rule = 0;
    my $spacing = '';
    my $comment = '';
    my $last_var_name = '';
    my $blank = 0;
    my $cond_true = 2; # undetermined ...

    while (<AM_FILE>)
    {
        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;
    while ($_)
    {
        if ($debug_on3) {
            my $aml = $_;
            chomp $aml;
            $aml =~ s/\r$//; # and remove CR, if present
            prt( "$. [$aml]\n" );
        }
        $_ .= "\n"
            unless substr ($_, -1, 1) eq "\n";

        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";
            &am_line_error ($., "blank line following trailing backslash")
                if $saw_bk;
        }
        elsif (/$COMMENT_PATTERN/o)
        {
            # Stick comments before the incoming macro or rule.
            $comment .= $spacing . $_;
            $spacing = '';
            &am_line_error ($., "comment following trailing backslash")
                if $saw_bk;
        }
        elsif ($saw_bk)
        {
            if ($was_rule)
            {
                $output_trailer .= join ('', @conditional_stack) . $_;
                $saw_bk = /\\$/;
            }
            else
            {
                $saw_bk = /\\$/;
                # Chop newline and backslash if this line is
                # continued.  ensure trailing whitespace exists.
                chop if $saw_bk;
                chop if $saw_bk;
                $contents{$last_var_name} .= ' '
                    unless $contents{$last_var_name} =~ /\s$/;
                $contents{$last_var_name} .= $_;
                if (@conditional_stack)
                {
                    $conditional{$last_var_name} .= &quote_cond_val ($_);
                }
            }
        }
        elsif (/$IF_PATTERN/o)
        {
            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 ($debug_on3);
                    $cond_true = 1;
                } else {
                    prt( "Found if $1, but NOT in cfg_defines ...\n" ) if ($debug_on3);
                    $cond_true = 0;
                }
            } else {
                &am_line_error ($., "$1 does not appear in AM_CONDITIONAL");
            }
            push (@conditional_stack, "\@" . $1 . "_TRUE\@");
        }
        elsif (/$ELSE_PATTERN/o)
        {
            if (! @conditional_stack)
            {
                &am_line_error ($., "else without if");
            }
            elsif ($conditional_stack[$#conditional_stack] =~ /_FALSE\@$/)
            {
                &am_line_error ($., "else after else");
            }
            else
            {
                $conditional_stack[$#conditional_stack]
                    =~ s/_TRUE\@$/_FALSE\@/;
            }
        }
        elsif (/$ENDIF_PATTERN/o)
        {
            if (! @conditional_stack)
            {
                &am_line_error ($., ": endif without if");
            }
            else
            {
                pop @conditional_stack;
            }
            $cond_true = 2; # undetermined ...
        }
        elsif (/$RULE_PATTERN/o)
        {
            # Found a rule.
            $was_rule = 1;
            if (defined $contents{$1}
                && (@conditional_stack
                ? ! defined $conditional{$1}
                : defined $conditional{$1}))
            {
                &am_line_error ($1,
                        "$1 defined both conditionally and unconditionally");
            }
            # Value here doesn't matter; for targets we only note
            # existence.
            $contents{$1} = 1;
            $targets{$1} = 1;
            my $cond_string = join ('', @conditional_stack);
            if (@conditional_stack)
            {
                if ($conditional{$1})
                {
                    &check_ambiguous_conditional ($1, $cond_string);
                    $conditional{$1} .= ' ';
                }
                else
                {
                    $conditional{$1} = '';
                }
                $conditional{$1} .= $cond_string . ' 1';
            }
            $content_lines{$1} = $.;
            $output_trailer .= $comment . $spacing . $cond_string . $_;
            $comment = $spacing = '';
            $saw_bk = /\\$/;

            # Check the rule for being a suffix rule. If so, store in
            # a hash.

            my $source_suffix;
            my $object_suffix;

            if (($source_suffix, $object_suffix) = ($1 =~ $SUFFIX_RULE_PATTERN)) 
            {
              $suffix_rules{$source_suffix} = $object_suffix;
              prt( "Sources ending in .$source_suffix become .$object_suffix\n" ) if $verbose;
              $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)
        {
            prt( "Found a macro definition. 1[$1] 2[$2] 3[$3] ...\n" ) if ($debug_on3);
            $was_rule = 0;
            $last_var_name = $1;
            if (defined $contents{$1}
            && (@conditional_stack
                ? ! defined $conditional{$1}
                : defined $conditional{$1}))
            {
                &am_line_error ($1,
                        "$1 defined both conditionally and unconditionally");
            }
            my $value;
            if ($3 ne '' && substr ($3, -1) eq "\\")
            {
                $value = substr ($3, 0, length ($3) - 1);
            }
            else
            {
                $value = $3;
            }
            my $type = $2;
            if ($type eq '+')
            {
                if (! defined $contents{$last_var_name}
                    && defined $configure_vars{$last_var_name})
                {
                    $contents{$last_var_name} = '@' . $last_var_name . '@';
                }
                $contents{$last_var_name} .= ' ' . $value;
            }
            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 ($debug_on3) {
                                    if ( $contents{$last_var_name} ne $value ) {
                                        prt( "NB: [$last_var_name] = [$contents{$last_var_name}]" .
                                            " replaced with [$value] (am_file=$am_file line=$.)\n" );
                                    }
                                }
                                $contents{$last_var_name} = $value;
                                $content_lines{$last_var_name} = $.;
                            }
                        } else {
                            # we are in the else FALSE state
                            if ($cond_true != 1) {
                                if ($debug_on3) {
                                    if ( $contents{$last_var_name} ne $value ) {
                                        prt( "NB: [$last_var_name] = [$contents{$last_var_name}]" .
                                            " replaced with [$value] (am_file=$am_file line=$.)\n" );
                                    }
                                }
                                $contents{$last_var_name} = $value;
                                $content_lines{$last_var_name} = $.;
                            }
                        }
                    }
                } else {
                    prt( "First setting [$last_var_name] = [$value] " .
                        "(am_file=$am_file line=$.)\n" ) if ($debug_on3);
                    $contents{$last_var_name} = $value;
                    # 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} = $.;
                }
            }
            my $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)
                        {
                            $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 = /\\$/;

            # Error if bogus.
            &am_line_error ($., "bad macro name \`$last_var_name'")
                if ! $is_ok_macro;
        }
        elsif (/$INCLUDE_PATTERN/o)
        {
                my ($path) = $1;

                if ($path =~ s/^\$\(top_srcdir\)\///)
                {
                    push (@include_stack, "\$\(top_srcdir\)/$path");
                }
                else
                {
                    $path =~ s/\$\(srcdir\)\///;
                    push (@include_stack, "\$\(srcdir\)/$path");
                    $path = $relative_dir . "/" . $path;
                }
                &read_am_file ($path);
        }
        else
        {
            # 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) . $_);
            $comment = $spacing = '';
            $saw_bk = /\\$/;
        }

        $_ = <AM_FILE>;
    }

    close(AM_FILE);
    $output_trailer .= $comment;

    &am_error ("unterminated conditionals: " . join (' ', @conditional_stack))
    if (@conditional_stack);
}

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 = ();

}

# 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;
}

# 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 am_error {
    my $msg = shift;
    mydie( $msg."\n" );
}

sub am_line_error
{
    my ($symbol, @args) = @_;
    prt( "am_line_error: am_file=[$am_file] sym=[$symbol] arg0=[$args[0]] ...\n" ) if ($debug_on3);
    if ($symbol && "$symbol" ne '-1')
    {
    my ($file) = "${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";
    $exit_status = 1;
    }
    else
    {
    &am_error (@args);
    }
}

sub generate_dsw
{
    my $name = shift;
    my $dsw_name = $root_dir . $name . '.dsw';
    open(DSW, ">$dsw_name")
    || mydie( "Can't create $dsw_name: $!\n" );

    prt( "Creating $dsw_name\n" ) if $verbose;

    print DSW <<"EOF";
Microsoft Developer Studio Workspace File, Format Version 6.00\r
# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE!\r
\r
###############################################################################\r
\r
EOF
    print DSW 'Project: ', "\"$name\"=\".\\", $name, ".dsp\" - Package Owner=<4>\r\n";
    print DSW <<"EOF";
\r
Package=<5>\r
{{{\r
}}}\r
\r
Package=<4>\r
{{{\r
}}}\r
\r
EOF

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

    print DSW <<"EOF";
###############################################################################\r
\r
Global:\r
\r
Package=<5>\r
{{{\r
}}}\r
\r
Package=<3>\r
{{{\r
}}}\r
\r
###############################################################################\r
\r
EOF
    close(DSW);
}

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 = shift;
    my $dsp_name = $root_dir . $name . '.dsp';

    open(DSP, ">$dsp_name")
    || mydie( "Can't create $dsp_name: $!\n" );

    prt( "Creating $dsp_name\n" ) if $verbose;

    print DSP expand_here(<<"EOF");
# Microsoft Developer Studio Project File - Name="$name" - Package Owner=<4>\r
# Microsoft Developer Studio Generated Build File, Format Version 6.00\r
# ** DO NOT EDIT **\r
\r
# TARGTYPE "Win32 (x86) Console Application" 0x0103\r
\r
CFG=$name - Win32 Debug\r
!MESSAGE This is not a valid makefile. To build this project using NMAKE,\r
!MESSAGE use the Export Makefile command and run\r
!MESSAGE \r
!MESSAGE NMAKE /f "$name.mak".\r
!MESSAGE \r
!MESSAGE You can specify a configuration when running NMAKE\r
!MESSAGE by defining the macro CFG on the command line. For example:\r
!MESSAGE \r
!MESSAGE NMAKE /f "$name.mak" CFG="$name - Win32 Debug"\r
!MESSAGE \r
!MESSAGE Possible choices for configuration are:\r
!MESSAGE \r
!MESSAGE "$name - Win32 Release" (based on "Win32 (x86) Console Application")\r
!MESSAGE "$name - Win32 Debug" (based on "Win32 (x86) Console Application")\r
!MESSAGE \r
\r
# Begin Project\r
# PROP AllowPerConfigDependencies 0\r
# PROP Scc_ProjName ""\r
# PROP Scc_LocalPath ""\r
CPP=cl.exe\r
RSC=rc.exe\r
\r
!IF  "\$(CFG)" == "$name - Win32 Release"\r
\r
# PROP Use_MFC 0\r
# PROP Use_Debug_Libraries 0\r
# PROP Output_Dir "Release"\r
# PROP Intermediate_Dir "Release"\r
# PROP Target_Dir ""\r
# ADD CPP /nologo /W3 /GX /O2 /D "NDEBUG" /D "WIN32" /D "_CONSOLE" /D "_MBCS" /FD /c %cflags%\r
# SUBTRACT CPP /YX\r
# ADD RSC /l 0xc09 /d "NDEBUG"\r
BSC32=bscmake.exe\r
# ADD BSC32 /nologo\r
LINK32=link.exe\r
# 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%\r
\r
!ELSEIF  "\$(CFG)" == "$name - Win32 Debug"\r
\r
# PROP Use_MFC 0\r
# PROP Use_Debug_Libraries 1\r
# PROP Output_Dir "Debug"\r
# PROP Intermediate_Dir "Debug"\r
# PROP Ignore_Export_Lib 0\r
# PROP Target_Dir ""\r
# ADD CPP /nologo /W3 /Gm /GX /ZI /Od /D "_DEBUG" /D "WIN32" /D "_CONSOLE" /D "_MBCS" /FR /FD /GZ /c %cflags%\r
# ADD RSC /l 0xc09 /d "_DEBUG"\r
BSC32=bscmake.exe\r
# ADD BSC32 /nologo\r
LINK32=link.exe\r
# 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%\r
\r
!ENDIF \r
\r
# Begin Target\r
\r
# Name "$name - Win32 Release"\r
# Name "$name - Win32 Debug"\r
EOF

    close(DSP);
}

sub static_lib_dsp_init
{
    my $name = shift;
    my $dsp_name = $root_dir . $name . '.dsp';

    open(DSP, ">$dsp_name")
    || mydie( "Can't create $dsp_name: $!\n" );

    prt( "Creating $dsp_name\n" ) if $verbose;

    print DSP expand_here(<<"EOF");
# Microsoft Developer Studio Project File - Name="$name" - Package Owner=<4>\r
# Microsoft Developer Studio Generated Build File, Format Version 6.00\r
# ** DO NOT EDIT **\r
\r
# TARGTYPE "Win32 (x86) Static Library" 0x0104\r
\r
CFG=$name - Win32 Debug\r
!MESSAGE This is not a valid makefile. To build this project using NMAKE,\r
!MESSAGE use the Export Makefile command and run\r
!MESSAGE \r
!MESSAGE NMAKE /f "$name.mak".\r
!MESSAGE \r
!MESSAGE You can specify a configuration when running NMAKE\r
!MESSAGE by defining the macro CFG on the command line. For example:\r
!MESSAGE \r
!MESSAGE NMAKE /f "$name.mak" CFG="$name - Win32 Debug"\r
!MESSAGE \r
!MESSAGE Possible choices for configuration are:\r
!MESSAGE \r
!MESSAGE "$name - Win32 Release" (based on "Win32 (x86) Static Library")\r
!MESSAGE "$name - Win32 Debug" (based on "Win32 (x86) Static Library")\r
!MESSAGE \r
\r
# Begin Project\r
# PROP AllowPerConfigDependencies 0\r
# PROP Scc_ProjName ""\r
# PROP Scc_LocalPath ""\r
CPP=cl.exe\r
RSC=rc.exe\r
\r
!IF  "\$(CFG)" == "$name - Win32 Release"\r
\r
# PROP Use_MFC 0\r
# PROP Use_Debug_Libraries 0\r
# PROP Output_Dir "Release"\r
# PROP Intermediate_Dir "Release"\r
# PROP Target_Dir ""\r
# ADD CPP /nologo /W3 /GX /O2 /D "NDEBUG" /D "WIN32" /D "_MBCS" /FD /c %cflags%\r
# ADD RSC /l 0x409 /d "NDEBUG"\r
BSC32=bscmake.exe\r
# ADD BASE BSC32 /nologo\r
# ADD BSC32 /nologo\r
LINK32=link.exe -lib\r
# ADD BASE LIB32 /nologo\r
# ADD LIB32 /nologo\r
\r
!ELSEIF  "\$(CFG)" == "$name - Win32 Debug"\r
\r
# PROP Use_MFC 0\r
# PROP Use_Debug_Libraries 1\r
# PROP Output_Dir "Debug"\r
# PROP Intermediate_Dir "Debug"\r
# PROP Target_Dir ""\r
# ADD CPP /nologo /W3 /GX /ZI /Od /D "_DEBUG" /D "WIN32" /D "_MBCS" /FR /FD /GZ /c %cflags%\r
# ADD RSC /l 0x409 /d "_DEBUG"\r
BSC32=bscmake.exe\r
# ADD BASE BSC32 /nologo\r
# ADD BSC32 /nologo\r
LINK32=link.exe -lib\r
# ADD BASE LIB32 /nologo\r
# ADD LIB32 /nologo\r
\r
!ENDIF \r
\r
# Begin Target\r
\r
# Name "$name - Win32 Release"\r
# Name "$name - Win32 Debug"\r
EOF

    close(DSP);
}

sub dsp_add_source_rule {
    my ($fh,$dsp_name,$group,$file,$dup) = @_;
    print $fh "# Begin Source File\r\n";
    print $fh "\r\n";
    print $fh "SOURCE=$file\r\n";
    if ($add_groups) {
        print $fh "\r\n";
        print $fh "!IF  \"\$(CFG)\" == \"$dsp_name - Win32 Release\"\r\n";
        print $fh "\r\n";
        print $fh "# PROP Intermediate_Dir \"Release\\$group\"\r\n";
        print $fh "# PROP Exclude_From_Build 1\r\n" if exclude_file($file);
        print $fh "\r\n";
        print $fh "!ELSEIF  \"\$(CFG)\" == \"$dsp_name - Win32 Debug\"\r\n";
        print $fh "\r\n";
        print $fh "# PROP Intermediate_Dir \"Debug\\$group\"\r\n";
        print $fh "# PROP Exclude_From_Build 1\r\n" if exclude_file($file);
        print $fh "\r\n";
        print $fh "!ENDIF \r\n";
        print $fh "\r\n";
    } elsif ($dup) {
        add_dupes_dir( \*$fh, $dsp_name );
    }
    print $fh "# End Source File\r\n";
}

sub dsp_add_group {
    my ($dsp_name,$makefile) = @_;
    my $base_dir = './';
    my $dsp_file = $root_dir . $dsp_name .'.dsp';
    prt( "dsp_add_group: using dsp_name=$dsp_file, and makefile=$makefile ...\n" ) if $verbose2;
    initialize_per_input();
    my $relative_dir = dirname($makefile);
    my $dupe = 0;
    my @files = ();
    my $key = '';
    my $group = 'Lib_Special';
    my $file = '';

    read_main_am_file($root_dir . $makefile . '.am');

    if ($write_old_dsp) {
        ###open(DSP, ">>$dsp_name" . '.dsp')
        open(DSP, ">>$dsp_file")
        || mydie( "Can't append to $dsp_file: $!\n" );
    }

    # preview the 'contents' to find 'group'
    # use 'noinst_LIBRARIES' macro
    foreach $key (keys %contents) {
        if ($key eq 'noinst_LIBRARIES') {
            @files = split(' ', $contents{$key});
            foreach $file (@files) {
                if ($file =~ /^lib([\w-]+)\.a/) {
                    $group = 'Lib_' . $1;
                    prt( "Group set to [$group] ...\n" ) if ($debug_on3);
                    last;
                }
            }
        }
    }

    # now extract 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/) {
            $group = 'Lib_' . $1;
            if ($add_groups && $write_old_dsp) {
                print DSP "# Begin Group \"$group\"\r\n";
                print DSP "\r\n";
                print DSP "# PROP Default_Filter \"\"\r\n";
            }
            @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( "Expanding variable $varname ...\n" ) if ($debug_on3);
                    foreach (split(' ', $contents{$varname})) {
                        $file = $src_dir . $_;
                        $dupe = add_2_source_list( $file, $group );
                        if ($write_old_dsp) {
                            dsp_add_source_rule(\*DSP, $dsp_name, $group, $file, $dupe);
                        }
                    }
                    prt( "Done expanding variable $varname ...\n" ) if ($debug_on3);
                } else {
                    $file = $src_dir . $_;
                    $dupe = add_2_source_list( $file, $group );
                    if ($write_old_dsp) {
                        dsp_add_source_rule(\*DSP, $dsp_name, $group, $file, $dupe);
                    }
                }
            }
            if ($add_groups && $write_old_dsp) {
                print DSP "# End Group\r\n";
            }

        }
        #elsif ($key =~ /(.*)_SOURCES/) {
        elsif ($key eq "fgfs_SOURCES") {
            $group = 'main';
            if ($add_groups && $write_old_dsp) {
                print DSP "# Begin Group \"$group\"\r\n";
                print DSP "\r\n";
                print DSP "# PROP Default_Filter \"\"\r\n";
            }
            @files = split(' ', $contents{$key});
            foreach (@files) {
                my $src_dir = $base_dir . $relative_dir . '/';
                $src_dir =~ s/\//\\/g; # fixup DOS path separators
                $file = $src_dir . $_;
                $dupe = add_2_source_list( $file, $group );
                if ($write_old_dsp) {
                    dsp_add_source_rule(\*DSP, $dsp_name, $group, $file, $dupe);
                }
            }
            if ($add_groups && $write_old_dsp) {
                print DSP "# End Group\r\n";
            }
        } else {
            # key is NOT ( Lib(.*)_a_SOURCES fgfs_SOURCES )
            if (($key eq 'EXTRA_DIST')||($key eq 'fgjs_SOURCES')) {
                @files = split(' ', $contents{$key});
                foreach my $fi (@files) {
                    my $ext = file_extension($fi);
                    $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 $verbose2;
                    } elsif (is_h_source_ext($ext)) {
                        push(@msvc_h_extra, $file);
                        prt( "Added [$file] to H EXTRA list\n" ) if $verbose2;
                    } else {
                        push(@msvc_o_extra, $file);
                        prt( "Added [$file] to other EXTRA list\n" ) if $verbose2;
                    }
                }
            } elsif ($key eq 'noinst_HEADERS') {
                # JSBSim has put the HEADERS in HERE
                @files = split(' ', $contents{$key});
                foreach (@files) {
                    $file = $base_dir . $relative_dir . '/' . $_;
                    $file =~ s/\//\\/g; # use DOS path sep
                    $dupe = add_2_source_list( $file, $group );
                }
            } 
        }
    }
    close(DSP) if $write_old_dsp;
}

sub dsp_finish {
    my $dsp_name = shift;
    my $dsp_file = $root_dir . $dsp_name . '.dsp';
    open(DSP, ">>$dsp_file")
    || mydie( "Can't append to $dsp_file: $!\n" );

    foreach my $r (@extra_sources) {
        print DSP "# Begin Source File\r\n\r\n";
        print DSP "$r\r\n";
        print DSP "# End Source File\r\n";
    }
    print DSP "# End Target\r\n";
    print DSP "# End Project\r\n";

    close(DSP);
}

# Return directory name of file.
sub dirname
{
    my ($file) = @_;
    my ($sub);

    ($sub = $file) =~ s,/+[^/]+$,,g;
    $sub = '.' if $sub eq $file;
    return $sub;
}

sub add_2_used_libs {
    my ($fil,$in) = @_;
    if (exists( $used_lib_paths{$in} ) ) {
        my @incs = split(/\|/ , $used_lib_paths{$in});
        my $got = 0;
        foreach my $i (@incs) {
            if ($i eq $fil) {
                $got = 1;
                last;
            }
        }
        if ( ! $got ) {
            $used_lib_paths{$in} .= '|'.$fil; # add new
        }
    } else {
        $used_lib_paths{$in} = $fil; # set first
    }
}

sub check_lib_paths {
    my $fil = shift;
    my $inc = '';
    my $ff = '';
    my $finc = '';
    my $fincr = '';
    my $fincd = '';
    my $found1 = 0;
    my $found2 = 0;
    my $found3 = 0;
    foreach $inc (@msvc_libs_paths) {
        $ff = $root_dir . $inc;
        if ( !(($ff =~ /\/$/) || ($ff =~ /\\$/)) ) {
            $ff .= '\\';
        }
        $ff .= $fil;
        if( -f $ff ) {
            $finc = $inc;
            $found1 = 1;
            last;
        }
    }
    foreach $inc (@msvc_rlibs_paths) {
        $ff = $root_dir . $inc;
        if ( !(($ff =~ /\/$/) || ($ff =~ /\\$/)) ) {
            $ff .= '\\';
        }
        $ff .= $fil;
        if( -f $ff ) {
            $fincr = $inc;
            $found2 = 1;
            last;
        }
    }
    foreach $inc (@msvc_dlibs_paths) {
        $ff = $root_dir . $inc;
        if ( !(($ff =~ /\/$/) || ($ff =~ /\\$/)) ) {
            $ff .= '\\';
        }
        $ff .= $fil;
        if( -f $ff ) {
            $fincd = $inc;
            $found3 = 1;
            last;
        }
    }
    if( $found1 || $found2 || $found3 ) {
        prt( "Found [$fil] in [$finc] [$ff] ...\n" ) if ($verbose2 && $found1);
        prt( "Found [$fil] in [$fincr] [$ff] ...\n" ) if ($verbose2 && $found2);
        prt( "Found [$fil] in [$fincd] [$ff] ...\n" ) if ($verbose2 && $found3);
        add_2_used_libs( $fil, $finc ) if $found1;
        add_2_used_libs( $fil, $fincr ) if $found2;
        add_2_used_libs( $fil, $fincd ) if $found3;
    } else {
        prt( "WARNING: Unable to locate $fil ...\n" ) if $verbose2;
    }
    return ($found1 + $found2 + $found3);
}

sub check_inc_paths {
    my $fil = shift;
    my $inc = '';
    my $ff = '';
    my $found = 0;
    if( ! $found ) {
        foreach $inc (@msvc_inc_paths) {
            $ff = $root_dir . $inc;
            if ( !(($ff =~ /\/$/) || ($ff =~ /\\$/)) ) {
                $ff .= '\\';
            }
            $ff .= $fil;
            ### print "Checking for $fil in $ff ...\n" if $verbose9;
            if( -f $ff ) {
                if (exists( $used_inc_paths{$inc} ) ) {
                    my @incs = split(/\|/ , $used_inc_paths{$inc});
                    my $got = 0;
                    foreach my $i (@incs) {
                        if ($i eq $fil) {
                            $got = 1;
                            last;
                        }
                    }
                    if ( ! $got ) {
                        $used_inc_paths{$inc} .= '|'.$fil; # add new
                    }
                } else {
                    $used_inc_paths{$inc} = $fil; # set first
                }
                $found = 1;
                last;
            }
        }
    }
    if( $found ) {
        prt( "Found $fil in $inc [$ff] ...\n" ) if $verbose2;
    } else {
        prt( "WARNING: Unable to locate $fil ...\n" ) if $verbose2;
    }
    return $found;
}

sub show_lib_found {
    my (@arr) = @_;
    foreach my $in (@arr) {
        if (exists( $used_lib_paths{$in} ) ) {
            my @ip = split(/\|/, $used_lib_paths{$in});
            prt( "On path [$root_dir][$in] found ".scalar @ip." items ...\n" );
            my $cntr = 0;
            $in .= '\\' if !($in =~ /(\\|\/)$/);
            foreach my $f (@ip) {
                $cntr++;
                prt( "$cntr ".$root_dir.$in.$f."\n" );
            }
        } else {
            prt( "Warning: Found nothing on [$root_dir][$in] ...\n" );
        }
    }
}


sub find_rel_file { # ( $sp1[1], @vc8_main_srcs );
    my ($fil, @arr) = @_;
    my $fil1 = lc($fil);
    $fil1 =~ s/^\.(\\|\/)//;
    $fil1 =~ s/\//\\/g;
    ###prt( "Finding [$fil1] ...\n" );
    foreach my $src (@arr) {
        my @sp = split(/\|/, $src);
        my $fil2 = lc($sp[0]);
        $fil2 =~ s/^\.\.(\\|\/)\.\.(\\|\/)//;
        $fil2 =~ s/\//\\/g;
        ###prt( "Comparing with [$fil2] ...\n" );
        if ($fil1 eq $fil2) {
            ###$am_to_vc8{$fil} = $sp[0];
            ###$am_to_vc8{$sp[0]} = ($fil . '=' . $src);
			if (exists($am_to_vc8{$sp[0]})) {
				$am_to_vc8{$sp[0]} .= '+' . $fil . '=' . $src;
			} else {
				$am_to_vc8{$sp[0]} = $fil . '=' . $src;
			}
            return 1;
        }
    }
    return 0;
}

sub find_vc8_file {
    my ($fil, @arr) = @_;
    my $fil2 = lc($fil);
    $fil2 =~ s/^\.\.(\\|\/)\.\.(\\|\/)//; # remove RELATIVE
    $fil2 =~ s/\//\\/g; # swap to DOS
    ###prt( "Finding [$fil2] ...\n" );
    foreach $fil (@arr) {
        my $fil1 = lc($fil);
        ###prt( "Comparing with [$fil1] ...\n" );
        $fil1 =~ s/^\.(\\|\/)//; # remove relative
        $fil1 =~ s/\//\\/g; # swap to DOS
        if ($fil2 eq $fil1) {
            return 1;
        }
    }
    return 0;
}

# The EXTRA_DIST have been put in
# @msvc_c_extra or @msvc_h_extra or @msvc_o_extra
sub is_in_extra {
    my $fil2 = shift;
    my $ext = file_extension($fil2);
    ###prt( "Finding [$fil2] ext[$ext]...\n" );
    if (is_c_source_ext($ext)) {
        ###prt( "Checking [$fil2] ext[$ext] in msvc_c_extra ...\n" );
        # check out @msvc_c_extra
        return (find_vc8_file( $fil2, @msvc_c_extra ));
    } elsif (is_h_source_ext($ext)) {
        ###prt( "Checking [$fil2] ext[$ext] in msvc_h_extra ...\n" );
        # check out @msvc_h_extra
        return (find_vc8_file( $fil2, @msvc_h_extra ));
    } else {
        prt( "NOT checking [$fil2] ext[$ext]...\n" ) if ($debug_on3);
        # check out @msvc_o_extra - not really
    }
    return 0;
}

sub find_in_vc8_srcs {
	my $fnd = 0;
	my ($fil, $im, $src) = @_;
	if ($im) {
		$fnd = find_rel_file( $fil, @vc8_main_srcs );
	} else {
		$fnd = find_rel_file( $fil, @vc8_lib_srcs );
	}
	if ($fnd == 0) {
		# try searching the opposite source set ...
		if ($im) {
			$fnd = find_rel_file( $fil, @vc8_lib_srcs );
		} else {
			$fnd = find_rel_file( $fil, @vc8_main_srcs );
		}
		if ($fnd == 0) {
			my $fl = $fil;
			$fl =~ s/^\.(\\|\/)//;
			my $ff = $root_dir.$fl;
			if( -f $ff ) {
				prt( "NOT FOUND, but file [$ff] EXISTS!\n" );
			}
		} else {
			$fnd = 2; # set found in 'other'
			prt( "NOTE: [$src] NOT Found in ". ($im ? "Main" : "Library") .
				" but FOUND in other???\n" );
		}
	}
	return $fnd;
}

sub find_in_vc8_hdrs {
	my $fnd = 0;
	my ($fil, $im, $src) = @_;
	if ($im) {
		$fnd = find_rel_file( $fil, @vc8_main_hdrs );
	} else {
		$fnd = find_rel_file( $fil, @vc8_lib_hdrs );
	}
	if ($fnd == 0) {
		# try searching the opposite source set ...
		if ($im) {
			$fnd = find_rel_file( $fil, @vc8_lib_hdrs );
		} else {
			$fnd = find_rel_file( $fil, @vc8_main_hdrs );
		}
		if ($fnd == 0) {
			my $fl = $fil;
			$fl =~ s/^\.(\\|\/)//;
			my $ff = $root_dir.$fl;
			if( -f $ff ) {
				prt( "NOT FOUND, but file [$ff] EXISTS!\n" );
			}
		} else {
			$fnd = 2; # set found in 'other'
			prt( "NOTE: [$src] NOT Found in ". ($im ? "Main" : "Library") .
				" but FOUND in other???\n" );
		}
	}
	return $fnd;
}

# file_in_dupes( $fil, $im, @vc8_dup_srcs )
sub file_in_dupes {
	my $fnd = 0;
	my ($fil, $im, @arr) = @_;
    my $fil1 = lc($fil);
    $fil1 =~ s/^\.(\\|\/)//; # remove relative
    $fil1 =~ s/\//\\/g; # ensure DOS seps
    ###prt( "Finding [$fil1] ...\n" );
    foreach my $src (@arr) {
		$fnd++;
        my @sp = split(/\|/, $src);
        my $fil2 = lc($sp[0]);
        $fil2 =~ s/^\.\.(\\|\/)\.\.(\\|\/)//; # remove relative
        $fil2 =~ s/\//\\/g; # ensure DOS seps
        ###prt( "Comparing with [$fil2] ...\n" );
        if ($fil1 eq $fil2) {
			return $fnd; # return offset plus 1
        }
    }
	return 0;
}


##########################################################################
## check_vc8_proj
## Have loaded and parsed am2dsp?.cfg file
## Have loaded and parsed configure.ac file
## Have loaded and parsed each Makefile.am file
## and have a set of SOURCES, HEADERS, EXTRA_DIST (including fgfs_SOURCES),
## and could now WRITE the DSW/DSP files ...
##
## Finally, LOAD and parse the vcproj files,
## and do a COMPARE of sources, headers with
## those from the Makefile.am files ... try to find what has to be
## ADDED, DELETED or MODIFIED so the vcproj files will function.
##
##########################################################################
sub check_vc8_proj {
    my $fil = '';
    if (read_vcproj() == 0) {
        my $cnt = 0;
		my $amsrcs = scalar @msvc_c_files;
		my $amhdrs = scalar @msvc_h_files;
		my $vc8srcs = (scalar @vc8_main_srcs + scalar @vc8_lib_srcs);
		my $vc8hdrs = (scalar @vc8_main_hdrs + scalar @vc8_lib_hdrs);
		my $amtotal = $amsrcs + $amhdrs;
		my $vc8total = $vc8srcs + $vc8hdrs;
		my $vc8dh = scalar @vc8_dup_hdrs;
		my $vc8dc = scalar @vc8_dup_srcs;
        # we have all the SOURCES, HEADERS, and CONFIGURATION information
        prt( "Load of VC8 project files: $vc8srcs sources, $vc8hdrs headers, ".
			"duplicates $vc8dc source, $vc8dh headers ...\n" );
        # check SOURCES (sources and headers)
        # the makefile.am sources and headers are in
        # foreach $src (@msvc_c_files)
        # foreach $src (@msvc_h_files)
        # each would be a relative path to $root_dir ...
        # and each in the form group|relsource|filename,
        # like 'Lib_Time|.\src\Time\light.cxx|light'

        # the VC8 project sources and headers are in
        # each is in the form 'relativepath|bgnline-endline'
        # like '..\..\src\main\main.cxx|279-282'
        # @vc8_main_hdrs = find_headers('main', @vc8_main_lines);
        # @vc8_main_srcs = find_sources('main', @vc8_main_lines);
        # @vc8_lib_hdrs = find_headers('library', @vc8_lib_lines);
        # @vc8_lib_srcs = find_sources('library', @vc8_lib_lines);
        # the 'relativepath' would be relative to $root_dir.$vc8_root = 'projects\\VC8\\';
        # Essentially 'Lib_Main' should be in @vc8_main_srcs, others in @vc8_lib_srcs
		# NOTE WELL: There MAY be DUPLICATED headers (and sources) in VC8!!!
		####################################################################
        prt( "\nSOURCE files - Comparing $amsrcs am with $vc8srcs vc8 sources...\n" );
        foreach my $src1 (@msvc_c_files) {
            my @sp1 = split(/\|/,$src1);
            $fil = $sp1[1];
            ###my $im = (lc($sp1[0]) eq 'lib_main') ? 1 : 0;
            my $im = ( $sp1[0] =~ /Main/i ) ? 1 : 0;
            my $fnd = find_in_vc8_srcs( $fil, $im, $src1 );
            if ( exclude_file( $fil ) ) {
                prt( "File [$src1] EXCLUDED FROM BUILD " .
					($fnd ? "but FOUND!" : "so NOT FOUND")."\n" );
                next;
            }
            if ($fnd == 0) {
                prt( "$fil NOT FOUND! $src1\n" ) if ($debug_on);
                push(@not_in_vc8, $src1);
            } else {
				$fnd = file_in_dupes( $fil, $im, @vc8_dup_srcs );
				if ($fnd) {
					$fnd--; # remove plus 1
					prt( "File [$src1] also in dupes [$vc8_dup_srcs[$fnd]]! " );
					# Note, stored main=library
					my @sp2 = split( /=/, $vc8_dup_srcs[$fnd] );
					# storeage of lines to DELETE
					if ($im) {
						# delete 'library' item
						prt( "DELETE lib $sp2[1]\n" );
						push(@vc8_lib_delete, $sp2[1]);
					} else {
						# delete 'main' item
						prt( "DELETE main $sp2[0]\n" );
						push(@vc8_main_delete, $sp2[0]);
					}
				}
			}
        }
        prt( "\nHEADER files - Comparing $amhdrs am with $vc8hdrs vc8 headers...\n" );
        foreach my $src1 (@msvc_h_files) {
            my @sp1 = split(/\|/,$src1);
            $fil = $sp1[1];
            my $im = (lc($sp1[0]) =~ /Main/i) ? 1 : 0;
            my $fnd = find_in_vc8_hdrs( $fil, $im, $src1 );
            if ( exclude_file( $fil ) ) {
                prt( "File [$src1] EXCLUDED FROM BUILD " .
					($fnd ? "but FOUND!" : "so NOT FOUND")."\n" );
                next;
            }
            if ($fnd == 0) {
                prt( "$fil NOT FOUND! $src1\n" ) if ($debug_on);
                push(@not_in_vc8, $src1);
            } else {
				# @vc8_dup_hdrs
				$fnd = file_in_dupes( $fil, $im, @vc8_dup_hdrs );
				if ($fnd) {
					$fnd--; # remove plus 1
					prt( "File [$src1] also in dupes [$vc8_dup_hdrs[$fnd]]! " );
					# Note, stored main=library
					my @sp2 = split( /=/, $vc8_dup_hdrs[$fnd] );
					# storeage of lines to DELETE
					if ($im) {
						# delete 'library' item
						prt( "DELETE lib $sp2[1]\n" );
						push(@vc8_lib_delete, $sp2[1]);
					} else {
						# delete 'main' item
						prt( "DELETE main $sp2[0]\n" );
						push(@vc8_main_delete, $sp2[0]);
					}
				}
			}
        }

		# RESULTS of Makefile.am files with VC8 files
        if (@not_in_vc8) {
            prt( "In comparing $amtotal Makefile.am sources with ".
				"$vc8total vcproj files,\n" );
            prt( "the following ".scalar @not_in_vc8." file(s) were NOT found?\n" );
            $cnt = 0;
            foreach $fil (@not_in_vc8) {
                my @sp1 = split(/\|/,$fil); # split into 3 - Librarygroup|relativesource|lcfiletitle
                my $ext = lc(file_extension( $sp1[1] ));
                $cnt++;
                prt( "$cnt [$fil] [$ext=". (is_c_source_ext($ext) ? "source" : "header") . "]\n" );
            }
        } else {
            prt( "Appears ALL $amtotal Makefile.am sources are in the ".
				"$vc8total vcproj files ...\n" );
        }

        # reverse compare VC8 that is NOT in am files
        # each FIND was put in this HASH $am_to_vc8{$sp[0]} = $fil;
        # Four (4) arrays to check
        # But have NOTED many ARE in EXTRA_DIST, thus should be
        # DELETED from the vcproj files
        # The EXTRA_DIST have been put in
        # @msvc_c_extra or @msvc_h_extra or @msvc_o_extra

        prt( "\nReverse compare: Those of $vc8total VC8 NOT in ".
					"$amtotal am files ...\n" );
		my $fcnt = 0;
        # $fil, @vc8_main_srcs
        foreach $fil (@vc8_main_srcs) {
            my @sp = split(/\|/, $fil);
            if ( exists($am_to_vc8{$sp[0]}) ) {
				$fcnt++;
			} else {
                push(@not_in_am, $fil);
            }
        }
        # $fil, @vc8_lib_srcs
        foreach $fil (@vc8_lib_srcs) {
            my @sp = split(/\|/, $fil);
            if ( exists($am_to_vc8{$sp[0]}) ) {
				$fcnt++;
			} else {
                push(@not_in_am, $fil);
            }
        }
        # $fil, @vc8_main_hdrs
        foreach $fil (@vc8_main_hdrs) {
            my @sp = split(/\|/, $fil);
            if ( exists($am_to_vc8{$sp[0]}) ) {
				$fcnt++;
			} else {
                push(@not_in_am, $fil);
            }
        }
        # $fil, @vc8_lib_hdrs );
        foreach $fil (@vc8_lib_hdrs) {
            my @sp = split(/\|/, $fil);
            if ( exists($am_to_vc8{$sp[0]}) ) {
				$fcnt++;
			} else {
                push(@not_in_am, $fil);
            }
        }
		my $diff = ($vc8total - (scalar @not_in_am + $vc8dh + $vc8dc + keys(%am_to_vc8)));
        if (@not_in_am) {
			$cnt = scalar @not_in_am;
            prt( "In comparing $vc8total vcproj sources with $amtotal Makefile.am files,\n" );
            prt( "the following $cnt file(s) were NOT found? (f=$fcnt)\n" );
			$cnt = 0;
            foreach $fil (@not_in_am) {
                my @sp1 = split(/\|/,$fil); # split into 3 - relativepath|line-numbers|group
	            my $im = ($sp1[2] eq 'main') ? 1 : 0;
                my $ext = lc(file_extension( $sp1[0] ));
                $cnt++;
                if ( is_in_extra( $sp1[0] ) ) {
                    prt( "$cnt [$fil] [$ext=". (is_c_source_ext($ext) ? "source" : "header") . "] IS IN EXTRA_DIST!\n" );
                } else {
                    prt( "$cnt [$fil] [$ext=". (is_c_source_ext($ext) ? "source" : "header") . "]\n" );
                }
				if ($im) {
					# delete 'main' item
					prt( "DELETE main [$fil]\n" );
					push(@vc8_main_delete, $fil);
				} else {
					# delete 'library' item
					prt( "DELETE lib [$fil]\n" );
					push(@vc8_lib_delete, $fil);
				}
            }
			$fcnt = keys(%am_to_vc8);
			prt( "This missed count $cnt + ".($vc8dh + $vc8dc)." dupes + $fcnt found should equal total ".
				"$vc8total, diff = $diff ". ($diff ? 'CHECK DIFFERENCE!' : 'ok')."\n");
            prt( "This LIST of $cnt file(s) SHOULD BE REMOVED from the vcproj files!\n" );

        } else {
            prt( "Appears ALL $vc8total vcproj sources are in $amtotal Makefile.am files,\n" );
        }

		if ($debug_on4 || $diff) {
			$cnt = 0;
			prt( "\nDebug list of ". keys(%am_to_vc8) . " am files FOUND in VC8 lists ...\n" );
			foreach my $key (keys %am_to_vc8) {
				$cnt++;
				#prt( "$cnt $key -> ".$am_to_vc8{$key}."\n" );
				prt( "$cnt ".$am_to_vc8{$key}."\n" );
			}
		}

		check_vc8_config();
		# check the OUTPUT
		# amend_vcproj();

    } else {
        prt( "FAILED to load of VC8 project files ...\n" );
    }

}

sub check_includes {
    my $fil = '';
    my $ff = '';
    my $cnt1 = 0;
    my $cnt2 = 0;
    my @missed = ();
    my @missed2 = ();
    my $inc = '';
    my @incpath = ();
    $cnt1 = scalar @msvc_dlibs_list + scalar @msvc_rlibs_list + scalar @msvc_libs_list;
    prt( "\nCheck 1: each $cnt1 additional library, in each library include path ...\n" );
    foreach $fil (@msvc_dlibs_list) {
        if( check_lib_paths( $fil ) == 0 ) {
            push(@missed, $fil);
        }
    }
    foreach $fil (@msvc_rlibs_list) {
        if( check_lib_paths( $fil ) == 0 ) {
            push(@missed, $fil);
        }
    }
    foreach $fil (@msvc_libs_list) {
        if( check_lib_paths( $fil ) == 0 ) {
            push(@missed, $fil);
        }
    }
    show_lib_found(@msvc_libs_paths);
    show_lib_found(@msvc_rlibs_paths);
    show_lib_found(@msvc_dlibs_paths);
    if( @missed ) {
        prt( "WARNING: Missed ". join(' ',@missed) . ".\n" );
        prt( "Check 'add_lib' and 'lib_path' in $src_cfg ...\n" );
    } else {
        prt( "Appears no libraries are is missing ...\n" );
    }
    prt( "Done 1: each $cnt1 additional library, in each library include path ...\n" );

    # check for a known set of INCLUDE (or source) files
    $cnt2 = scalar @test_headers;
    prt( "\nCheck 2: each of $cnt2 test headers, in each include path ...\n" );
    foreach $fil (@test_headers) {
        if( check_inc_paths( $fil ) == 0 ) {
            push(@missed2, $fil);
        }
    }
    foreach $inc (@msvc_inc_paths) {
        if (exists( $used_inc_paths{$inc} ) ) {
            @incpath = split(/\|/, $used_inc_paths{$inc});
            prt( "On path [$root_dir][$inc] found ".scalar @incpath." items ...\n" );
            my $cntr = 0;
            foreach $fil (@incpath) {
                $cntr++;
                if ( ! ($inc =~ /(\\|\/)$/) ) {
                    $inc .= '\\';
                }
                prt( "$cntr ".$root_dir.$inc.$fil."\n" );
            }
        } else {
            prt( "Warning: Found nothing on [$root_dir][$inc] ...\n" );
        }
    }
    if( @missed2 ) {
        prt( "WARNING: Missed ". join(' ',@missed2) . ".\n" );
        prt( "Check 'include_path' in $src_cfg ...\n" );
    } else {
        prt( "Appears no test sources, headers are missing ...\n" );
    }

    prt( "Done checking $cnt1 libraries, and $cnt2 test includes ...\n" );

    check_vc8_proj();

    # NO RETURN FROM HERE
    mydie( "End check of libraries and include files ... aborting ...\n" );
}

# some simple utility functions
sub pos_of_last_slash {
    my $fil = shift;
    my $in1 = rindex( $fil, '/' );
    my $in2 = rindex( $fil, '\\' );
    my $pos = -1;
    # if BOTH exist
    if (($in1 >= 0) && ($in2 >= 0)) {
        # get the LAST
        if ($in1 > $in2) {
            $pos = $in1;
        } else {
            $pos = $in2;
        }
    } elsif ($in1 >= 0 ) {
        $pos = $in1;
    } elsif ($in2 >= 0 ) {
        $pos = $in2;
    }
    return $pos;
}

sub file_extension {
    my $fil = shift;
    my $pos = pos_of_last_slash($fil);
    my $last = rindex( $fil, '.' );
    my $ext = '';
    if ( $last >= 0 ) {
        if ($pos >= 0) {
            if ($last > $pos) {
                $ext = substr($fil, $last + 1);
            }
        } else {
            $ext = substr($fil, $last + 1);
        }
    }
    return $ext;
}

sub file_title {
    my $fil = shift;
    my $pos = pos_of_last_slash($fil);
    my $last = rindex( $fil, '.' );
    my $tit = '';
    if ($last >= 0) {
        if ($pos >= 0) {
            if ($last > $pos) {
                ###print "Using 1 substr( $fil, $pos+1, $last - $pos - 1 ) ...\n"; 
                $tit = substr( $fil, $pos+1, $last - $pos - 1 ); 
            } else {
                ###print "Using 2 substr( $fil, $pos+1 ) ...\n"; 
                $tit = substr( $fil, $pos+1 ); 
            }
        } else {
            ###print "Using 3 substr( $fil, 0, $last ) ...\n"; 
            $tit = substr( $fil, 0, $last ); 
        }
    } elsif ($pos >= 0) {
        ###print "Using 4 substr( $fil, $pos+1 ) ...\n"; 
        $tit = substr( $fil, $pos+1 ); 
    } else {
        ###print "Using 5 no slash, no dot ...\n"; 
        $tit = $fil;
    }
    return $tit;
}

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

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


sub add_2_source_list {
    my ($fil, $grp) = @_;
    my $fe = file_extension($fil);
    my $ft = lc(file_title($fil));
    my $src = ($grp . '|' . $fil . '|' . $ft);
    my $ret = 0;
    ###if (($fe eq 'c')||($fe eq 'cxx')||($fe eq 'cpp')) {
    if ( is_c_source_ext($fe) ) {
        prt( "Add $src to C list\n" ) if $verbose2;
        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);
    } else {
        prt( "Add $src to H list\n" ) if $verbose2;
        push(@msvc_h_files, $src);
    }
    return $ret;
}


sub add_dupes_dir {
    my ($fh, $pack) = @_;
    print $fh "\r\n";
    print $fh "!IF  \"\$(CFG)\" == \"$pack - Win32 Release\"\r\n";
    print $fh "\r\n";
    print $fh "# PROP Intermediate_Dir \"Release\\Dupes\"\r\n";
    print $fh "\r\n";
    print $fh "!ELSEIF  \"\$(CFG)\" == \"$pack - Win32 Debug\"\r\n";
    print $fh "\r\n";
    print $fh "# PROP Intermediate_Dir \"Debug\\Dupes\"\r\n";
    print $fh "\r\n";
    print $fh "!ENDIF\r\n"; 
    print $fh "\r\n";
}

sub write_new_dsp {
    ###my $new_pack = 'FGFS';
    my $new_pack = $dsp_package;
    my $src;
    my $dsp_file = $root_dir . $new_pack .'.dsp';
    my @bits = ();
    my @done = ();
    my $group = '';
    my $pgrp = '';
    my $tit = '';
    my $isdupe = 0;
    if ($static_lib) {
        static_lib_dsp_init($new_pack);
    } else {
        console_app_dsp_init($new_pack);
    }
    open(DSP, ">>$dsp_file") || mydie( "Can't append to $dsp_file: $!\n" );
    if ( ! $add_groups) {
        print DSP "# Begin Group \"Source Files\"\r\n";
        print DSP "\r\n";
        print DSP "# PROP Default_Filter \"cpp;c;cxx;rc;def;r;odl;idl;hpj;bat\"\r\n";
    }
    foreach $src (@msvc_c_files) {
        prt( "Processing $src from array ...\n" ) if $verbose2;
        @bits = split( /\|/, $src ); # get file title, name and group
        $group = 'Lib_' . $bits[0];
        $tit = $bits[2];
        $isdupe = 0;
        if ($add_groups && ($group ne $pgrp)) {
            print DSP "# Begin Group \"$group\"\r\n";
            print DSP "\r\n";
            print DSP "# PROP Default_Filter \"\"\r\n";
        } else {
            # not adding groups, check duplicate names
            foreach my $tt (@done) {
                if( $tt eq $tit ) {
                    $isdupe = 1;
                    last;
                }
            }
        }
        dsp_add_source_rule(\*DSP, $new_pack, $group, $bits[1], $isdupe);
        if ( !$add_groups && $isdupe) {
            prt( "Processed a DUPLICATE $tit from array ...\n" ) if $verbose2;
            prt( "Bits = ".$bits[0]."|".$bits[1].'|'.$bits[2]. " ...\n" ) if $verbose2;
        }
        push(@done, $tit);
        if ($add_groups && ($group ne $pgrp)) {
            print DSP "# End Group\r\n";
        }
        $pgrp = $group;
    }
    if ( !$add_groups) {
        print DSP "# End Group\r\n";
    }

    # just the HEADER files
    print DSP "# Begin Group \"Header Files\"\r\n";
    print DSP "\r\n";
    print DSP "# PROP Default_Filter \"h;hpp;hxx;hm;inl\"\r\n";
    my $savgrp = $add_groups;
    $add_groups = 0;
    foreach $src (@msvc_h_files) {
        @bits = split( /\|/, $src ); # get file title, name and group
        $group = 'Lib_' . $bits[2];
        dsp_add_source_rule(\*DSP, $new_pack, $group, $bits[1], 0);
    }
    print DSP "# End Group\r\n";
    close(DSP);
    $add_groups = $savgrp;
    dsp_finish($new_pack);
    generate_dsw($new_pack);
    prt( "Done ".$root_dir.$new_pack." DSP and DSW files ...\n" );

}

sub prt {
    my $msg = shift;
    print $msg;
    if ($write_log) {
        print $LOG $msg;
    }
}

sub mydie {
    my (@msg) = @_;
    prt( @msg );
    die "ABORTING\n";
}

sub trim_line {
    my ($l) = shift;
    chomp $l;
    $l =~ s/\r$//; # and remove CR, if present
    $l =~ s/\t/ /g;
    $l =~ s/\s\s/ /g while ($l =~ /\s\s/);
    #$l = substr($l,1) while ($l =~ /^\s/);
    #$l = substr($l,0,length($l)-1) while (($l =~ /\s$/)&&(length($l)));
    for ($l) {
        s/^\s+//;
        s/\s+$//;
    }
    return $l;
}

###############################################################################
## VC8 STUFF BELOW
###############################################################################

sub find_item3 {
    my ($grp, $st1, $st2, $st3, $st31, $st3x, $stf, @ll) = @_;
    my @hdrs = ();
    my $ln1 = '';
    my $ln = '';
    my $lb = 0;
    my $le = 0;
    my $lc = 0;
    my $st = 0;
    my $lns = ''; # accumulate until stack closed
    my $tok = '';
    my $lnsb = 0;
    prt( "Got [".$st1."], [$st2], [$st3], [$st31], [$st3x], [$stf]... \n" ) if $debug_on2;
    foreach $ln1 (@ll) {
        chomp $ln1;
        $ln1 =~ s/\r$//; # and remove CR, if present
        prt( "$lc [$ln1] state=$st\n" ) if ($debug_on3);
        $ln .= $ln1; # accumulate line
        if ($ln1 =~ /</) {
            $lb = $lc;
        }
        if ($ln1 =~ />/) {
            $le = $lc; # xml ends on this line
        }
        if ($ln =~ />/) {
            if ($st == 0) {
                # searching for 'VisualStudioProject'
                #if ($ln =~ /<VisualStudioProject/) {
                if ($ln =~ /$st1/) {
                    $st = 1;
                }
            } elsif ($st == 1) {
                # seraching for 'Files'
                if ($ln =~ /$st2/) {
                    $st = 2;
                }
            } elsif ($st == 2) {
                # searching for 'Filter'
                if ($ln =~ /$st3/) {
                    #if ($ln =~ /Name=\"Header Files\"/) {
                    if ($ln =~ /$st31/) {
                        prt( "Enter 3 ... found $st31 ... ".trim_line($ln)."\n") if $debug_on2;
                        $st = 3;
                    }
                }
            } elsif ($st == 3) {
                #if ($ln =~ /<\/Filter/) {
                if ($ln =~ /$st3x/) {
                    $st = 2;
                #} elsif ( $ln =~ /(<File)+(\s)+(RelativePath=\")+([\.\\\w]+)+(\")+(.)+/ ) {
                } elsif ( $ln =~ /$stf/ ) {
                    $tok = $4;
                    $lns = trim_line($ln);
                    $lnsb = $lb;
                    $st = 4;
                    prt( "1[$1] 2[$2] 3[$3] 4[$4] 5[$5] 6[$6] (".trim_line($ln).")\n" ) if $debug_on2;
                }
            } elsif ($st == 4) {
                $lns .= trim_line($ln);
                if ( $ln =~ /<\/File>/ ) {
                    push(@hdrs, $tok . '|' . $lnsb . '-' . $le . '|' . $grp);
                    prt( "End file $tok, $lnsb - $le (".trim_line($lns).")\n" ) if $debug_on2;
                    $st = 3; # back to level 3
                    $lns = '';
                }
            } 
            $ln = ''; # restart line accumuation
        }
        $lc++; # bump line counter
    }
    return @hdrs;
}


sub find_headers {
    my ($grp, @ll) = @_;
    my $st1 = '<VisualStudioProject';
    my $st2 = '<Files';
    my $st3 = '<Filter';
    my $st31 = 'Name="Header Files"';
    my $st3x = '<\/Filter';
    my $stf = '(<File)(\\s+)(RelativePath=\\")([\\.\\\\\\w-]+)(\\"+)(.+)';
    ###prt( "Got [".$st1."], [$st2], [$st3], [$st31], [$st3x], [$stf]... \n" );
    my @hdrs = find_item3( $grp, $st1, $st2, $st3, $st31, $st3x, $stf, @ll );
    return @hdrs;
}

sub find_sources {
    my ($grp, @ll) = @_;
    my $st1 = '<VisualStudioProject';
    my $st2 = '<Files';
    my $st3 = '<Filter';
    my $st31 = 'Name="Source Files"';
    my $st3x = '<\/Filter';
    ###my $stf = '(<File)+(\\s)+(RelativePath=\\")+([\\.\\\\\\w]+)+(\\")+(.)+';
    my $stf = '(<File)(\\s+)(RelativePath=\\")([\\.\\\\\\w-]+)(\\"+)(.)';
    ###prt( "Got [".$st1."], [$st2], [$st3], [$st31], [$st3x], [$stf]... \n" );
    my @hdrs = find_item3( $grp, $st1, $st2, $st3, $st31, $st3x, $stf, @ll );
    return @hdrs;
}


sub find_hash3 {
    my ($st1, $st2, $st3, $st31, $st3x, $stf1, $stf2, @ll) = @_;
    my %hdrs = ();
    my $ln1 = '';
    my $ln = '';
    my $lb = 0;
    my $le = 0;
    my $lc = 0;
    my $st = 0;
    my $nm = '';
    prt( "Got [".$st1."], [$st2], [$st3], [$st31], [$st3x], [$stf1] [$stf2 ... \n" ) if $debug_on2;
    foreach $ln1 (@ll) {
        chomp $ln1;
        $ln1 =~ s/\r$//; # and remove CR, if present
        $ln .= $ln1;
        if ($ln1 =~ /</) {
            $lb = $lc;
        }
        if ($ln1 =~ />/) {
            $le = $lc;
        }
        if ($ln =~ />/) {
            if ($st == 0) {
                # searching for 'VisualStudioProject'
                #if ($ln =~ /<VisualStudioProject/) {
                if ($ln =~ /$st1/) {
                    $st = 1;
                }
            } elsif ($st == 1) {
                # searching for 'Configurations'
                if ($ln =~ /$st2/) {
                    $st = 2;
                }
            } elsif ($st == 2) {
                # searching for 'Configuration'
                if ($ln =~ /$st3/) {
                    #if ($ln =~ /Name=\"Debug|Win32\"/) {
                    if ($ln =~ /$st31/) {
                        prt( "Enter 3 ... found $st31 1[$1] 2[$2] 3[%3]... ".trim_line($ln)."\n") if $debug_on2;
                        $nm = $2 . '|'; # set the NAME
                        if ($ln =~ /(IntermediateDirectory=\")(\w+?)(\")/) {
                            $hdrs{$nm.'IntermediateDirectory'} = '' . $lb . '-' . $le;
                            prt( "Got IntDir 1[$1] 2[$2] 3[$3] ...\n" ) if $debug_on2;
                        }
                        $st = 3;
                    }
                }
            } elsif ($st == 3) {
                my $tln = trim_line($ln);
                #if ($ln =~ /<\/Configuration/) {
                if ($tln =~ /$st3x/) {
                    prt( "Exit 3 ... found $st3x ... ".trim_line($ln)."\n") if $debug_on2;
                    $st = 2;
                } elsif ( $tln =~ /(^<Tool)+(\s)+(Name=\"VCCLCompilerTool\")+(.+)+(>)/ ) {
                ###} elsif ( $ln =~ /$stf/ ) {
                    $hdrs{$nm.'VCCLCompilerTool'} = '' . $lb . '-' . $le;
                    prt( "1[$1] 2[$2] 3[$3] 4[$4] 5[$5] 6[$6] \n(".trim_line($ln).")\n" ) if $debug_on2;
                } elsif ( $tln =~ /(^<Tool)+(\s)+(Name=\"VCLinkerTool\")+(.+)+(>)/ ) {
                    $hdrs{$nm.'VCLinkerTool'} = '' . $lb . '-' . $le;
                    prt( "1[$1] 2[$2] 3[$3] 4[$4] 5[$5] 6[$6] \n(".trim_line($ln).")\n" ) if $debug_on2;
                }
            } 
            $ln = ''; # restart line accumuation
        }
        $lc++; # bump line counter
    }
    return %hdrs;
}

##sub find_debug {
sub find_config {
    my (@ll) = @_;
    my $st1 = '<VisualStudioProject';
    my $st2 = '<Configurations';
    my $st3 = '<Configuration';
    my $st31 = '(Name=")(Debug|Release)(\|Win32")';
    my $st3x = '<\/Configuration';
    my $stf1 = '(<Tool)+(\\s)+(Name="VCCLCompilerTool")';
    my $stf2 = '(<Tool)+(\\s)+(Name="VCCLCompilerTool")';
    ###prt( "Got [".$st1."], [$st2], [$st3], [$st31], [$st3x], [$stf1] [$stf2] ... \n" );
    my %hdrs = find_hash3( $st1, $st2, $st3, $st31, $st3x, $stf1, $stf2, @ll );
    return %hdrs;
}

# sub get_lines( $configd{$key}, @main_lines );
# extract a line, like 5-5, or set of lines, like 23-27
# from an array of lines - return 'massaged' single line
sub get_lines {
    my ($lns, @arr) = @_;
    my $rln = '';
    my @ft = split( /-/, $lns );
    my $cnt = scalar @arr;
    if (($ft[0] < $cnt)&&($ft[0] <= $ft[1])&&($ft[1] < $cnt)) {
        if ($ft[0] == $ft[1]) { # ONE line
            $rln = trim_line($arr[$ft[0]]);
        } else { # multiple lines
            for (my $i = $ft[0]; $i <= $ft[1]; $i++ ) {
                $rln .= trim_line( $arr[$i] );
                if ($rln =~ /\s$/) {
                    # ok, got a space
                } elsif ($i < $ft[1]) {
                    $rln .= ' ';
                }
            }
        }
    }
    return trim_line($rln);
}

sub get_raw_lines {
    my ($lns, @arr) = @_;
    my @rln = ();
    my @ft = split( /-/, $lns );
    my $cnt = scalar @arr;
    if (($ft[0] < $cnt)&&($ft[0] <= $ft[1])&&($ft[1] < $cnt)) {
        if ($ft[0] == $ft[1]) { # ONE line
            push(@rln, $arr[$ft[0]] );
        } else { # multiple lines
            for (my $i = $ft[0]; $i <= $ft[1]; $i++ ) {
                push(@rln, $arr[$i] );
            }
        }
    }
    return @rln;
}


sub clear_arrays {
    # configuration stuff
	%msvc8_confi = ();
    $msvc8_dintd = '';
    $msvc8_rintd = '';
    # compiler stuff
    @msvc8_dincs = ();
    @msvc8_ddefs = ();
    @msvc8_rincs = ();
    @msvc8_rdefs = ();
    # linker stuff
    @msvc8_dlibs = ();
    @msvc8_dpath = ();
    @msvc8_rlibs = ();
    @msvc8_rpath = ();
    # other items
    $warn = '';
}

sub process_vc8_lines {
    my (@mlines) = @_;
    my ($key, $line, $nm, $tool, $msg, $item);
    clear_arrays();
    ###my %configd = find_config(@mlines);
    ###for my $key (keys %configd) {
    %msvc8_confi = find_config(@mlines);
    for my $key (keys %msvc8_confi) {
        prt( "key = $key => value = " . $msvc8_confi{$key} . "\n" ) if $debug_on2;
        $line = get_lines( $msvc8_confi{$key}, @mlines );
        my ($nm,$tool) = split( /\|/, $key );
        ###prt( "line[$line]nm=$nm tool=$tool\n" );
        if ($tool eq 'VCCLCompilerTool') {
            if ($line =~ /(AdditionalIncludeDirectories)(=)(\")(.+?)(\")(.+)/) {
                $item = $4;
                $msg = "$nm Incs=4[$item] 5[$5] ";
                if ($nm eq 'Debug') {
                    @msvc8_dincs = split(/;/, $item);
                    $msg .= 'added to msvc8_dincs';
                } elsif ($nm eq 'Release') {
                    @msvc8_rincs = split(/;/, $item);
                    $msg .= 'added to msvc8_rincs';
                } else {
                    prt( "WARNING: Unknown configuration ... $nm ???\n" );
                    $warn .= "WARNING: Unknown configuration ... $nm ???\n";
                }
                prt( "$msg\n" ) if $debug_on2;
            }
            if ($line =~ /(PreprocessorDefinitions)(=)(\")(.+?)(\")(.+)/) {
                $item = $4;
                $msg = "$nm Defs=4[$item] 5[$5] ";
                if ($nm eq 'Debug') {
                    @msvc8_ddefs = split(/;/, $item);
                    $msg .= 'added to msvc8_ddefs';
                } elsif ($nm eq 'Release') {
                    @msvc8_rdefs = split(/;/, $item);
                    $msg .= 'added to msvc8_rdefs';
                } else {
                    prt( "WARNING: Unknown configuration ...$nm ???\n" );
                    $warn .= "WARNING: Unknown configuration ...$nm ???\n";
                }
                prt( "$msg\n" ) if $debug_on2;
            }

        } elsif ($tool eq 'VCLinkerTool') {
            if ($line =~ /(AdditionalDependencies)(=)(\")(.+?)(\")(.+)/) {
                $item = $4;
                $msg = "$nm Libs=4[$item] 5[$5] ";
                if ($nm eq 'Debug') {
                    @msvc8_dlibs = split(/ /, $item);
                    $msg .= 'added to msvc8_dlibs';
                } elsif ($nm eq 'Release') {
                    @msvc8_rlibs = split(/ /, $item);
                    $msg .= 'added to msvc8_rlibs';
                } else {
                    prt( "WARNING: Unknown configuration ...$nm ???\n" );
                    $warn .= "WARNING: Unknown configuration ...$nm ???\n";
                }
                prt( "$msg\n" ) if $debug_on2;
            }
            if ($line =~ /(AdditionalLibraryDirectories)(=)(\")(.+?)(\")(.+)/) {
                $item = $4;
                ###prt( "Paths=4[$4] 5[$5]\n" );
                $item =~ s/&quot;/\"/g;
                $msg = "$nm Paths=$item 5[$5] ";
                if ($nm eq 'Debug') {
                    @msvc8_dpath = split(/;/, $item);
                    $msg .= 'added to msvc8_dpath';
                } elsif ($nm eq 'Release') {
                    @msvc8_rpath = split(/;/, $item);
                    $msg .= 'added to msvc8_rpath';
                } else {
                    prt( "WARNING: Unknown configuration ...$nm ???\n" );
                    $warn .= "WARNING: Unknown configuration ...$nm ???\n";
                }
                prt( "$msg\n" ) if $debug_on2;
            }
        } elsif ($tool = 'IntermediateDirectory') {
            if ($line =~ /(IntermediateDirectory)(=)(\")(.+?)(\")(.+)/) {
                $item = $4;
                $msg = "$nm Paths=$item 5[$5] ";
                if ($nm eq 'Debug') {
                    $msvc8_dintd = $item;
                    $msg .= 'added to msvc8_dintd';
                } elsif ($nm eq 'Release') {
                    $msvc8_rintd = $item;
                    $msg .= 'added to msvc8_rintd';
                } else {
                    prt( "WARNING: Unknown configuration ...$nm ???\n" );
                    $warn .= "WARNING: Unknown configuration ...$nm ???\n";
                }
                prt( "$msg\n" ) if $debug_on2;
            }
        } else {
            prt( "WARNING: Unknown Tool [$tool] ...\n" );
            $warn .= "WARNING: Unknown Tool [$tool] ...\n";
        }
    }
}

sub copy_main_items {
	%main_msvc8_confi = %msvc8_confi;
    $main_msvc8_dintd = $msvc8_dintd;
    $main_msvc8_rintd = $msvc8_rintd;
    # compiler stuff
    @main_msvc8_dincs = @msvc8_dincs;
    @main_msvc8_ddefs = @msvc8_ddefs;
    @main_msvc8_rincs = @msvc8_rincs;
    @main_msvc8_rdefs = @msvc8_rdefs;
    # linker stuff
    @main_msvc8_dlibs = @msvc8_dlibs;
    @main_msvc8_dpath = @msvc8_dpath;
    @main_msvc8_rlibs = @msvc8_rlibs;
    @main_msvc8_rpath = @msvc8_rpath;
    $main_warn = $warn;
}

sub copy_lib_items {
	%lib_msvc8_confi = %msvc8_confi;
    $lib_msvc8_dintd = $msvc8_dintd;
    $lib_msvc8_rintd = $msvc8_rintd;
    # compiler stuff
    @lib_msvc8_dincs = @msvc8_dincs;
    @lib_msvc8_ddefs = @msvc8_ddefs;
    @lib_msvc8_rincs = @msvc8_rincs;
    @lib_msvc8_rdefs = @msvc8_rdefs;
    # linker stuff
    @lib_msvc8_dlibs = @msvc8_dlibs;
    @lib_msvc8_dpath = @msvc8_dpath;
    @lib_msvc8_rlibs = @msvc8_rlibs;
    @lib_msvc8_rpath = @msvc8_rpath;
    $lib_warn = $warn;
}

#############################################################
## read_vcproj
## Load and parse -
## = $root_dir . 'projects\VC8\FlightGearLib.vcproj';
## = $root_dir . 'projects\VC8\FlightGear.vcproj';
##
## Original files lines are stored in
## @vc8_lib_lines, and @vc8_main_lines
## Extract the SOURCES and HEADERS to
## @vc8_main_srcs, @vc8_lib_srcs,
## @vc8_main_hdrs, @vc8_lib_hdrs
## Process the vc8 configuration section, and store info in
##
## For MAIN %main_msvc8_confi on @vc8_main_lines gives
## $main_msvc8_dintd, $main_msvc8_rintd
## @main_msvc8_dincs, @main_msvc8_ddefs
## @main_msvc8_rincs, @main_msvc8_rdefs
## @main_msvc8_dlibs, @main_msvc8_dpath
## @main_msvc8_rlibs, @main_msvc8_rpath
## $main_warn
##
## For LIBRARY %lib_msvc8_confi on @vc8_lib_lines gives
## $lib_msvc8_dintd, $lib_msvc8_rintd
## compiler stuff
## @lib_msvc8_dincs, @lib_msvc8_ddefs
## @lib_msvc8_rincs, @lib_msvc8_rdefs
## linker stuff
## @lib_msvc8_dlibs, @lib_msvc8_dpath
## @lib_msvc8_rlibs, @lib_msvc8_rpath
## $lib_warn
##
## each array contains the 'relativefilename | filelines'
## The filelines will allow modification of those lines in
## the original line array, so NEW modified files can be
## written ...
## Added a search for file in BOTH 'library' and 'main'
## and results to @vc8_dup_hdrs and @vc8_dup_srcs,
## which holds the two lines, separated by '=' sign.
#############################################################
sub read_vcproj {
    my $line = '';
    my $line1 = '';
    my $cnt = 0;
    if ( ! -f $vc8_src_lib ) {
        prt( "AWK: Unable to locate [$vc8_src_lib] file ...\n" );
        return 1;
    }
    if ( ! -f $vc8_src_main ) {
        prt( "AWK: Unable to locate [$vc8_src_main] file ...\n" );
        return 2;
    }

    open IF, "<$vc8_src_lib" or mydie( "Can not OPEN $vc8_src_lib!\n" );
    @vc8_lib_lines = <IF>; # slurp whole file, to an array of lines
    close(IF);

    open IF, "<$vc8_src_main" or mydie( "Can not OPEN $vc8_src_main!\n");
    @vc8_main_lines = <IF>; # slurp whole file, to an array of lines
    close(IF);

    my $lc_lib = scalar @vc8_lib_lines;
    my $lc_main = scalar @vc8_main_lines;

    prt( "Loaded $vc8_src_lib of $lc_lib lines ...\n" );
    prt( "Loaded $vc8_src_main of $lc_main lines ...\n" );

    prt( "Finding headers in vc8_main_lines ...\n" );
    @vc8_main_hdrs = find_headers('main', @vc8_main_lines);
    if ($debug_on3) {
        prt( "Listing ".scalar @vc8_main_hdrs." header lines in vc8_main_lines ...\n" );
        $cnt = show_sh_lines(1, @vc8_main_hdrs);
        prt( "Listed $cnt headers in vc8_main_lines ...\n" );
    }

    prt( "Finding source in vc8_main_lines ...\n" );
    @vc8_main_srcs = find_sources('main', @vc8_main_lines);
    if ($debug_on3) {
        prt( "Listing ".scalar @vc8_main_srcs." source lines in vc8_main_lines ...\n" );
        $cnt = show_sh_lines(2, @vc8_main_srcs);
        prt( "Listed $cnt sources in vc8_main_lines ...\n" );
    }

    prt( "Finding headers in lib_lines ...\n" );
    @vc8_lib_hdrs = find_headers('library', @vc8_lib_lines);
    if ($debug_on3) {
        prt( "Listing ".scalar @vc8_lib_hdrs." header lines in vc8_lib_lines ...\n" );
        $cnt = show_sh_lines(3, @vc8_lib_hdrs);
        prt( "Listed $cnt headers in vc8_lib_lines ...\n" );
    }
    prt( "Finding source in vc8_lib_lines ...\n" );
    @vc8_lib_srcs = find_sources('library', @vc8_lib_lines);
    if ($debug_on3) {
        prt( "Listing ".scalar @vc8_lib_srcs." source lines in vc8_lib_lines ...\n" );
        $cnt = show_sh_lines(4, @vc8_lib_srcs);
        prt( "Listed $cnt sources in vc8_lib_lines ...\n" );
    }

	# check if there are any duplicate file names
	# sort of SANITY CHECK ONLY, since it is to be EXPECTED for HEADERS
	# Note, if found, stored main=library
	prt( "Doing a 'duplicate' check ...\n" );
	$cnt = 0;
	foreach $line (@vc8_main_hdrs) {
		my @sp1 = split( /\|/, $line );
		my $ext1 = file_extension($sp1[0]);
		if ( ! is_h_source_ext($ext1) ) {
			prt( "WARNING 3: NOT correct file extension! [$line]\n" );
		}
		foreach my $ln (@vc8_lib_hdrs) {
			my @sp2 = split( /\|/, $ln );
			my $ext2 = file_extension($sp2[0]);
			if ( ! is_h_source_ext($ext2) ) {
				prt( "WARNING 3: NOT correct file extension! [$ln]\n" );
			}
			if (lc($sp1[0]) eq lc($sp2[0])) {
				push(@vc8_dup_hdrs, ($line . '=' . $ln));
				prt( "WARNING 2: Duplicate headers [$line][$ln]\n" );
				$cnt++;
			}
		}
	}
	# BUT NOT FOR SOURCES
	foreach $line (@vc8_main_srcs) {
		my @sp1 = split( /\|/, $line );
		my $ext1 = file_extension($sp1[0]);
		if ( ! is_c_source_ext($ext1) ) {
			prt( "WARNING 3: NOT correct file extension! [$line]\n" );
		}
		foreach my $ln (@vc8_lib_srcs) {
			my @sp2 = split( /\|/, $ln );
			my $ext2 = file_extension($sp2[0]);
			if ( ! is_c_source_ext($ext2) ) {
				prt( "WARNING 3: NOT correct file extension! [$ln]\n" );
			}
			if (lc($sp1[0]) eq lc($sp2[0])) {
				# Note, if found, stored main=library
				push(@vc8_dup_srcs, ($line . '=' . $ln));
				prt( "WARNING 2: Duplicate sources [$line][$ln]\n" );
				$cnt++;
			}
		}
	}
	if ($cnt) {
		prt( "Above list of $cnt DUPLICATE items. Duplicate SOURCES should be resolved ...\n" );
	}

    prt( "\nProcessing vc8_main_lines ... to extract configuration items ...\n" );
    process_vc8_lines(@vc8_main_lines);
    copy_main_items(); # copy into persistant variables
    show_main_arrays() if $debug_on3;
    prt( "Done vc8_main_lines for configuration items ...\n" );

    prt( "\nProcessing vc8_lib_lines ... to extract configuration items ...\n" );
    process_vc8_lines(@vc8_lib_lines);
    copy_lib_items(); # copy into persistant variables
    show_lib_arrays() if $debug_on3;
    prt( "Done vc8_lib_lines for configuration items ...\n" );

    return 0;
}


######################################################################
## MAINLY DEBUG ONLY THINGS
######################################################################
########################################################################
## show_arrays
## Used only for a DEBUG display
########################################################################
sub show_arrays {
    my $line = '';
    prt( "\nDebug IntDir=$msvc8_dintd, and Release IntDir=$msvc8_rintd ...\n" );
    # compiler stuff
    prt( "\nDebug compiler includes ... msvc8_dincs\n" );
    foreach $line (@msvc8_dincs) {
        prt( "$line\n" );
    }
    prt( "\nDebug compiler DEFINES ... msvc8_ddefs\n" );
    foreach $line (@msvc8_ddefs) {
        prt( "$line\n" );
    }
    prt( "\nRelease compiler includes ... msvc8_rincs\n" );
    foreach $line (@msvc8_rincs) {
        prt( "$line\n" );
    }
    prt( "\nRelease compiler DEFINES ... msvc8_rdefs\n" );
    foreach $line (@msvc8_rdefs) {
        prt( "$line\n" );
    }
    # linker stuff
    prt( "\nDebug linker LIBS ... msvc8_dlibs\n" );
    foreach $line (@msvc8_dlibs) {
        prt( "$line\n" );
    }
    prt( "\nDebug linker PATHS ... msvc8_dpath\n" );
    foreach $line (@msvc8_dpath) {
        prt( "$line\n" );
    }
    prt( "\nRelease linker LIBS ... msvc8_rlibs\n" );
    foreach $line (@msvc8_rlibs) {
        prt( "$line\n" );
    }
    prt( "\nRelease linker PATHS ... msvc8_rpath\n" );
    foreach $line (@msvc8_rpath) {
        prt( "$line\n" );
    }
    prt( "\nWARNINGS, if any\n$warn\n" );
}

########################################################################
## show_main_arrays
## Used only for a DEBUG display
########################################################################
sub show_main_arrays {
    my $line = '';
    prt( "\nDebug IntDir=$main_msvc8_dintd, and Release IntDir=$main_msvc8_rintd ...\n" );
    # compiler stuff
    prt( "\nDebug compiler includes ...  main_msvc8_dincs\n" );
    foreach $line (@main_msvc8_dincs) {
        prt( "$line\n" );
    }
    prt( "\nDebug compiler DEFINES ...  main_msvc8_ddefs\n" );
    foreach $line (@main_msvc8_ddefs) {
        prt( "$line\n" );
    }
    prt( "\nRelease compiler includes ...  main_msvc8_rincs\n" );
    foreach $line (@main_msvc8_rincs) {
        prt( "$line\n" );
    }
    prt( "\nRelease compiler DEFINES ...  main_msvc8_rdefs\n" );
    foreach $line (@main_msvc8_rdefs) {
        prt( "$line\n" );
    }
    # linker stuff
    prt( "\nDebug linker LIBS ...  main_msvc8_dlibs\n" );
    foreach $line (@main_msvc8_dlibs) {
        prt( "$line\n" );
    }
    prt( "\nDebug linker PATHS ...  main_msvc8_dpath\n" );
    foreach $line (@main_msvc8_dpath) {
        prt( "$line\n" );
    }
    prt( "\nRelease linker LIBS ...  main_msvc8_rlibs\n" );
    foreach $line (@main_msvc8_rlibs) {
        prt( "$line\n" );
    }
    prt( "\nRelease linker PATHS ...  main_msvc8_rpath\n" );
    foreach $line (@main_msvc8_rpath) {
        prt( "$line\n" );
    }
    prt( "\nWARNINGS, if any\n$main_warn\n" );
}

########################################################################
## show_lib_arrays
## Used only for a DEBUG display
########################################################################
sub show_lib_arrays {
    my $line = '';
    prt( "\nDebug IntDir=$lib_msvc8_dintd, and Release IntDir=$lib_msvc8_rintd ...\n" );
    # compiler stuff
    prt( "\nDebug compiler includes ...  lib_msvc8_dincs\n" );
    foreach $line (@lib_msvc8_dincs) {
        prt( "$line\n" );
    }
    prt( "\nDebug compiler DEFINES ...  lib_msvc8_ddefs\n" );
    foreach $line (@lib_msvc8_ddefs) {
        prt( "$line\n" );
    }
    prt( "\nRelease compiler includes ...  lib_msvc8_rincs\n" );
    foreach $line (@lib_msvc8_rincs) {
        prt( "$line\n" );
    }
    prt( "\nRelease compiler DEFINES ...  lib_msvc8_rdefs\n" );
    foreach $line (@lib_msvc8_rdefs) {
        prt( "$line\n" );
    }
    # linker stuff
    prt( "\nDebug linker LIBS ...  lib_msvc8_dlibs\n" );
    foreach $line (@lib_msvc8_dlibs) {
        prt( "$line\n" );
    }
    prt( "\nDebug linker PATHS ...  lib_msvc8_dpath\n" );
    foreach $line (@lib_msvc8_dpath) {
        prt( "$line\n" );
    }
    prt( "\nRelease linker LIBS ...  lib_msvc8_rlibs\n" );
    foreach $line (@lib_msvc8_rlibs) {
        prt( "$line\n" );
    }
    prt( "\nRelease linker PATHS ...  lib_msvc8_rpath\n" );
    foreach $line (@lib_msvc8_rpath) {
        prt( "$line\n" );
    }
    prt( "\nWARNINGS, if any\n$lib_warn\n" );
}

########################################################################
## show_sh_lines
## Used only for a DEBUG display
########################################################################
sub show_sh_lines {
    my ($t, @arr) = @_;
    my $cnt = 0;
    foreach my $ln (@arr) {
        $cnt++;
        prt( $ln."\n" );
        if ($debug_on2) {
            my @sp = split( /\|/, $ln ); # get source, LINE NUMBERS, and GROUP
            if (scalar @sp >= 3) {
                if ($t == 1) {
                    # @vc8_main_lines - headers
                    prt( get_lines( $sp[1], @vc8_main_lines ) );
                    prt( "\n" );
                } elsif ($t == 2) {
                    # @vc8_main_lines - sources
                    prt( get_lines( $sp[1], @vc8_main_lines ) );
                    prt( "\n" );
                } elsif ($t == 3) {
                    # @vc8_lib_lines - headers
                    prt( get_lines( $sp[1], @vc8_lib_lines ) );
                    prt( "\n" );
                } elsif ($t == 4) {
                    # @vc8_lib_lines - sources
                    prt( get_lines( $sp[1], @vc8_lib_lines ) );
                    prt( "\n" );
                } else {
                    prt( "\nWARNING: Can NOT pass [$t] to this service ...\n" );
                }
            } else {
                prt( "\nWARNING: Line is NOT name|lines format ...\n" );
            }
        }
    }
}

#####################################################
## prt_list
## Debug output of line list, with some rough
## indenting ...
#####################################################
sub prt_list {
    my (@list) = @_;
    my $ind = '';
    foreach my $line (@list) {
        if ($line =~ /^</) {
            if ($line =~ /\/>/) {
                # end xml same line
            } elsif ($line =~ /^<\//) {
                $ind = substr($ind, 1) if (length($ind));
            } else {
                # $ind .= ' ';
            }
        }
        prt( $ind.$line."\n" );
        if ($line =~ /^</) {
            if ($line =~ /\/>/) {
                # end xml same line
            } elsif ($line =~ /^<\//) {
                # $ind = substr($ind, 1) if (length($ind));
            } else {
                $ind .= ' ';
            }
        }
    }
}


################################################################
## amend_vcproj
## The idea it to 'copy' the original line arrays, making
## modifications, adding or subtracting lines, into to a
## new array, then write that out to an .tmp file.
## Then, rename the original to .old, or .bak, if .old
## already exists, then rename the .tmp to vcproj
## In this way attempting to RETAIN the original file,
## in case it all fails, or some other problem is encountered,
## the USER still has the ORIGINAL file available.
##
## There may be files to DELETE, or ADD, and configuration
## lines may need to be MODIFIED ...
##
################################################################
sub amend_vcproj {
	my $cl = 0;
	my $org_vc1 = $root_dir . $vc8_def_lib;
	my $org_vc2 = $root_dir . $vc8_def_main;
	my $out_vc1 = $org_vc1 . '.tmp';
	my $out_vc2 = $org_vc2 . '.tmp';
	my $bak_vc1 = $org_vc1 . '.old';
	my $bak_vc2 = $org_vc2 . '.old';

	# create the TEMPORARY FILES, aborting if either FAIL
	open OF1, ">$out_vc1" or mydie( "YEEK! Unable to create [$out_vc1] ...\n" );
	open OF2, ">$out_vc2" or mydie( "YEEK! Unable to create [$out_vc2] ...\n" );

	my $line = '';
	my @new_vclib = ();
	my @new_vcmain = ();
	my %del_lines = ();
	my @sp = ();
	my @sp2 = ();
	my $num = 0;
	my @deleted = ();
	prt( "Modifying the vc8_lib_lines ...\n" );
	$cl = 0;
	# storeage of lines to DELETE
	# delete 'library' item
	# push(@vc8_lib_delete, $sp2[1]);
	# typical line [..\..\src\main\renderer.cxx|2905-2908|library]
	%del_lines = ();
	foreach $line (@vc8_lib_delete) {
		@sp = split( /\|/, $line );
		@sp2 = split( /-/, $sp[1] );
		$num = $sp2[0];
		$del_lines{$num} = 1;
		while ($num < $sp2[1]) {
			$num++; # bump to next
			$del_lines{$num} = 1;
		}
	}
	foreach $line (@vc8_lib_lines) {
		# do any fix, deletion, or addition
		chomp $line;
        $line =~ s/\r$//; # and remove CR, if present
		if ( exists $del_lines{$cl}) {
			push(@deleted, ($cl . '[' . $line . ']') );
		} else {
			push(@new_vclib, $line);
		}
		$cl++;
	}
	if ($debug_on3 && @deleted) {
		prt( "Deleted following ".scalar @deleted." lines ...\n" );
		foreach $line (@deleted) {
			prt( "$line\n" );
		}
	}

	prt( "Modifying the vc8_main_lines ...\n" );
	$cl = 0;
	# delete 'main' item
	# push(@vc8_main_delete, $sp2[0]);
	%del_lines = ();
	@deleted = ();
	foreach $line (@vc8_main_delete) {
		@sp = split( /\|/, $line );
		@sp2 = split( /-/, $sp[1] );
		$num = $sp2[0];
		$del_lines{$num} = 1;
		while ($num < $sp2[1]) {
			$num++; # bump to next
			$del_lines{$num} = 1;
		}
	}
	foreach $line (@vc8_main_lines) {
		# do any fix, deletion, or addition
		chomp $line;
        $line =~ s/\r$//; # and remove CR, if present
		if ( exists $del_lines{$cl}) {
			push(@deleted, ($cl . '[' . $line . ']') );
		} else {
			push(@new_vcmain, $line);
		}
		$cl++;
	}
	if ($debug_on3 && @deleted) {
		prt( "Deleted following ".scalar @deleted." lines ...\n" );
		foreach $line (@deleted) {
			prt( "$line\n" );
		}
	}

	prt( "Writing the new lib lines to $out_vc1 ...\n" );
	foreach $line (@new_vclib) {
		print OF1 "$line\n";
	}

	prt( "Writing the new main lines to $out_vc2 ...\n" );
	foreach $line (@new_vcmain) {
		print OF2 "$line\n";
	}

	# close the output files
	close OF1;
	close OF2;

	# PERFORM THE RENAMING
	###############################################
	# IF either .old already exist, change to .bak
	if (( -f $bak_vc1 ) || ( -f $bak_vc1 )) {
		$bak_vc1 = $org_vc1 . '.bak';
		$bak_vc2 = $org_vc2 . '.bak';
		# remove any existing .bak, if exists
		unlink $bak_vc1 if ( -f $bak_vc1 );
		unlink $bak_vc2 if ( -f $bak_vc2 );
	}

	# rename the CURRENT to .old or .bak
	rename $org_vc1, $bak_vc1;
	rename $org_vc2, $bak_vc2;
	# rename the NEW to current
	rename $out_vc1, $org_vc1;
	rename $out_vc2, $org_vc2;
	# all DONE!!!
	##############################################
}

sub check_vc8_config {
	# have collected show_main_arrays
	# %main_msvc8_confi contains configuration keys, which can produce -
	# Debug IntDir=$main_msvc8_dintd, and Release IntDir=$main_msvc8_rintd
	# compiler stuff
	# Debug compiler includes ... @main_msvc8_dincs
	# Debug compiler DEFINES ... @main_msvc8_ddefs
	# Release compiler includes ... @main_msvc8_rincs
	# Release compiler DEFINES ... @main_msvc8_rdefs
	# linker stuff
	# Debug linker LIBS ... @main_msvc8_dlibs
	# Debug linker PATHS ... @main_msvc8_dpath
	# Release linker LIBS ... @main_msvc8_rlibs
	# Release linker PATHS ... @main_msvc8_rpath
	# WARNINGS, if any ... $main_warn
	#
	# Similarly, for library, collected show_lib_arrays
	# %lib_msvc8_confi contains configuration keys, which can produce -
	# Debug IntDir=$lib_msvc8_dintd, and Release IntDir=$lib_msvc8_rintd
	# compiler stuff
	# Debug compiler includes ...  @lib_msvc8_dincs
	# Debug compiler DEFINES ...  @lib_msvc8_ddefs
	# Release compiler includes ...  @lib_msvc8_rincs
	# Release compiler DEFINES ...  @lib_msvc8_rdefs
	# linker stuff
	# Debug linker LIBS ...  @lib_msvc8_dlibs
	# Debug linker PATHS ...  @lib_msvc8_dpath
	# Release linker LIBS ...  @lib_msvc8_rlibs
	# Release linker PATHS ...  @lib_msvc8_rpath
	# and WARNINGS, if any ... $lib_warn

	# check HEADERS and INCLUDE folders
	# check DEFINES
	my @items = qw(AdditionalIncludeDirectories PreprocessorDefinitions AdditionalDependencies
		AdditionalLibraryDirectories);
	my %hitems = ( AdditionalIncludeDirectories => ';',
		PreprocessorDefinitions => ';',
		AdditionalDependencies => ' ',
		AdditionalLibraryDirectories => ';',
		IntermediateDirectory => ';' );
	my %config_set = ();
	my $icnt = scalar @items;
	prt( "\nList of MAIN configuration items ...\n" ) if ($debug_on5);
	my $nums = '';
	my $num = 0;
	my @sp = ();
	my @arr = ();
	my $ln = '';
	my $i = 0;
	my $item = '';
	my $sep = ';';
	my $it = '';
	my $itm = '';
	my $key = '';
	my $ckey = '';
	foreach $key (keys %main_msvc8_confi) {
		$nums = $main_msvc8_confi{$key};
		@sp = split( /-/, $nums );
		$num = $sp[0];
		prt( "$key -> $nums\n" ) if ($debug_on5);
		@arr = get_raw_lines($nums, @vc8_main_lines);
		foreach $ln (@arr) {
			chomp $ln;
			$ln =~ s/\r$//; # and remove CR, if present
			###prt( "$num [$ln]\n" );
            #if ($ln =~ /\s+AdditionalIncludeDirectories=\"(.+)\"/) {
			#			prt( "$num FOUND AdditionalIncludeDirectories=[$1]\n" );
			#} elsif ( $ln =~ /\s+PreprocessorDefinitions=\"(.+)\"/ ) {
			#			prt( "$num FOUND PreprocessorDefinitions=[$1]\n" );
			#} elsif ( $ln =~ /\s+AdditionalDependencies=\"(.+)\"/ ) {
			#			prt( "$num FOUND AdditionalDependencies=[$1]\n" );
			#} elsif ( $ln =~ /\s+AdditionalLibraryDirectories=\"(.+)\"/ ) {
			#			prt( "$num FOUND AdditionalLibraryDirectories=[$1]\n" );
			#} else {
			#	prt( "$num [$ln]\n" );
			#}
			#for ($i = 0; $i < $icnt; $i++) {
			#	$item = $items[$i];
			#	if ($ln =~ /\s+($item)(=\")(.+)(\")/ ) {
			#		prt( "$num FOUND 1[$1] 2[$2] 3[$3] 4[$4]\n" );
			#		last;
			#	}
			#}
			@sp = ();
			foreach $item (keys %hitems) {
				$sep = $hitems{$item};
				if ($ln =~ /\s+($item)(=\")(.+)(\")/ ) {
					$itm = $3;
					$itm =~ s/&quot;/\"/g;
					prt( "$num FOUND 1[$1] 2[$2] 3[$itm] 4[$4]\n" ) if ($debug_on5);
					@sp = split( /$sep/, $itm );
					if ($debug_on5) {
						foreach $it (@sp) {
							prt( "$it\n" );
						}
					}
					# put into config set 
					$ckey = ($key . '|' . $item . '|main');
					$config_set{$ckey} = join('|',@sp);
					last;
				}
			}
			if ( ! @sp ) {
				prt( "$num [$ln]\n" ) if ($debug_on5);
			}
			$num++;
		}
	}
	prt( "\nList of LIBRARY configuration items ...\n" ) if ($debug_on5);
	foreach $key (keys %lib_msvc8_confi) {
		$nums = $lib_msvc8_confi{$key};
		@sp = split( /-/, $nums );
		$num = $sp[0];
		prt( "$key -> $nums\n" ) if ($debug_on5);
		@arr = get_raw_lines($nums, @vc8_lib_lines);
		foreach $ln (@arr) {
			chomp $ln;
			$ln =~ s/\r$//; # and remove CR, if present
			###prt( "$num [$ln]\n" );
			#for ($i = 0; $i < $icnt; $i++) {
			#	$item = $items[$i];
			#	if ($ln =~ /\s+($item)(=\")(.+)(\")/ ) {
			#		prt( "$num FOUND 1[$1] 2[$2] 3[$3] 4[$4]\n" );
			#		last;
			#	}
			#}
			#if ($i == $icnt) {
			#	prt( "$num [$ln]\n" );
			#}
			@sp = ();
			foreach $item (keys %hitems) {
				$sep = $hitems{$item};
				if ($ln =~ /\s+($item)(=\")(.+)(\")/ ) {
					$itm = $3;
					$itm =~ s/&quot;/\"/g;
					prt( "$num FOUND 1[$1] 2[$2] 3[$itm] 4[$4]\n" ) if ($debug_on5);
					@sp = split( /$sep/, $itm );
					if ($debug_on5) {
						foreach $it (@sp) {
							prt( "$it\n" );
						}
					}
					$ckey = ($key . '|' . $item . '|library');
					$config_set{$ckey} = join('|',@sp);
					last;
				}
			}
			if ( ! @sp ) {
				prt( "$num [$ln]\n" ) if ($debug_on5);
			}
			$num++;
		}
	}

	if ($debug_on5) {
		prt( "\nSimple output of the vc8 config set ... sorted on the keys \n" );
		foreach $ckey (sort keys %config_set) {
			prt( "$ckey -> ".$config_set{$ckey}."\n" );
		}
	}
	# the set of keys, and some values, should be something like ...
	# Debug|IntermediateDirectory|IntermediateDirectory|library -> FGDebug
	# Debug|IntermediateDirectory|IntermediateDirectory|main -> Debug
	# Debug|VCCLCompilerTool|AdditionalIncludeDirectories|library -> ../../../|../../../Simgear|...
	# Debug|VCCLCompilerTool|AdditionalIncludeDirectories|main -> ../../../|../../../Simgear|...
	# Debug|VCCLCompilerTool|PreprocessorDefinitions|library -> WIN32|_DEBUG|_WINDOWS|ENABLE_THREADS|...
	# Debug|VCCLCompilerTool|PreprocessorDefinitions|main -> WIN32|_DEBUG|_WINDOWS|ENABLE_THREADS|...
	# Debug|VCLinkerTool|AdditionalDependencies|main -> FlightgearLib.lib|Simgear.lib|fnt_d.lib|...
	# Debug|VCLinkerTool|AdditionalLibraryDirectories|main -> "FG$(IntDir)"|../../../plib/|...
	# Release|IntermediateDirectory|IntermediateDirectory|library -> FGRelease
	# Release|IntermediateDirectory|IntermediateDirectory|main -> Release
	# Release|VCCLCompilerTool|AdditionalIncludeDirectories|library -> ../../../|../../../Simgear|...
	# Release|VCCLCompilerTool|AdditionalIncludeDirectories|main -> ../../../|../../../Simgear|...
	# Release|VCCLCompilerTool|PreprocessorDefinitions|library -> WIN32|NDEBUG|_WINDOWS|PTW32_STATIC_LIB|...
	# Release|VCCLCompilerTool|PreprocessorDefinitions|main -> WIN32|NDEBUG|_CONSOLE|ENABLE_THREADS|...
	# Release|VCLinkerTool|AdditionalDependencies|main -> FlightgearLib.lib|Simgear.lib|fnt.lib|...
	# Release|VCLinkerTool|AdditionalLibraryDirectories|main -> "FG$(IntDir)"|../../../plib/|...

	my @def_w32_defines = qw( WIN32 NDEBUG|_DEBUG _WINDOWS _CRT_SECURE_NO_DEPRECATE
		_CONST_CORRECT_OVERLOADS _USE_MATH_DEFINES NOMINMAX PTW32_STATIC_LIB|_CONSOLE );
	my @def_w32_libs = qw( wsock32.lib|ws2_32.lib advapi32.lib comdlg32.lib shell32.lib user32.lib );
	if ($debug_on5) {
		foreach $ckey (@def_w32_defines) {
			prt( "$ckey\n" );
		}
		foreach $ckey (@def_w32_libs) {
			prt( "$ckey\n" );
		}
	}
}

# eof - am2dsp5.pl
