#!/usr/bin/perl -w
# NAME: make2cmake.pl
# AIM: Given an nmake 'makefile' try to generatet the equivalent cmake CMakeLists.txt
# 18/07/2012 - Initial cut
use strict;
use warnings;
use File::Basename;  # split path ($name,$dir,$ext) = fileparse($file [, qr/\.[^.]*/] )
use File::Spec; # File::Spec->rel2abs($rel);
use Cwd;
my $os = $^O;
my $perl_dir = '/home/geoff/bin';
my $PATH_SEP = '/';
my $temp_dir = '/tmp';
if ($os =~ /win/i) {
    $perl_dir = 'C:\GTools\perl';
    $temp_dir = $perl_dir;
    $PATH_SEP = "\\";
}
unshift(@INC, $perl_dir);
require 'lib_utils.pl' or die "Unable to load 'lib_utils.pl' Check paths in \@INC...\n";
require 'lib_params.pl' or die "Unable to load 'lib_params.pl'! Check location and \@INC content.\n";
# log file stuff
our ($LF);
my $pgmname = $0;
if ($pgmname =~ /(\\|\/)/) {
    my @tmpsp = split(/(\\|\/)/,$pgmname);
    $pgmname = $tmpsp[-1];
}
my $outfile = $temp_dir.$PATH_SEP."temp.$pgmname.txt";
open_log($outfile);

# user variables
my $VERS = "0.0.1 2012-07-18";
my $load_log = 0;
my $in_file = '';
my $verbosity = 0;
my $out_file = '';

# debug
my $debug_on = 1;
my $def_file = 'C:\Projects\notepad-plus\scintilla\win32\scintilla.mak';

### program variables
my @warnings = ();
my $cwd = cwd();
my %subst = ();
my %subs_not_found = ();
my %targets_deps = ();
my %targets_acts = ();
my %targets_file = ();
my ($rparams);

# shared variables
########################################
### SHARED RESOURCES, VALUES
### ========================
our $fix_relative_sources = 1;
our %g_user_subs = ();    # supplied by USER INPUT
our %g_user_condits = (); # conditionals supplied by the user
# Auto output does the following -
# For libaries
# Debug:  '/out:"lib\barD.lib"'
# Release:'/out:"lib\barD.lib"'
# for programs
# Debug:  '/out:"bin\fooD.exe"'
# Release:'/out:"bin\foo.exe"'
# This also 'adds' missing 'include' files
#Bit:   1: Use 'Debug\$proj_name', and 'Release\$proj_name' for intermediate and out directories
#Bit:   2: Set output to lib, or bin, and names to fooD.lib/foo.lib or barD.exe/bar.exe
#Bit:   4: Set program dependence per library output directories
#Bit:   8: Add 'msvc' to input file directory, if no target directory given
#Bit:  16: Add program library dependencies, if any, to DSW file output.
#Bit:  32: Add all necessary headers to the DSP file. That is scan the sources for #include "foo.h", etc.
#Bit:  64: Write a blank header group even there are no header files for that component.
#Bit: 128: Add defined item of HAVE_CONFIG_H to all DSP files.
#Bit: 256: Exclude projects in SUBDIRS protected by a DEFINITION macro, else include ALL.
#Bit: 512: Unconditionally add ANY libraries build, and NOT excluded to the last application
#Bit:1024: If NO users conditional, do sustitution, if at all possible, regardless of TRUE or FALSE
#Bit:2048: Add User -L dependent libraries to each application
#Bit: These can be given as an integer, or the form 2+8, etc. Note using -1 sets ALL bits on.
#Bit: Bit 32 really slows down the DSP creation, since it involves scanning every line of the sources.
my $auto_max_bit = 512;
our $auto_on_flag = -1; #Bit: ALL ON by default = ${$rparams}{'CURR_AUTO_ON_FLAG'}
sub get_curr_auto_flag() { return $auto_on_flag; }
#my ($g_in_name, $g_in_dir);
#my ($root_file, $root_folder);
#sub get_root_dir() { return $root_folder; }
our $exit_value = 0;
# But SOME Makefile.am will use specific 'paths' so the above can FAIL to find
# a file, so the following two 'try harder' options, will do a full 'root'
# directory SCAN, and search for the file of that name in the scanned files
our $try_harder = 1;
our $try_much_harder = 1;
# ==============================================================================
our $process_subdir = 0;
our $warn_on_plus = 0;
# ==============================================================================
# NOTE: Usually a Makefile.am contains SOURCE file names 'relative' to itself,
# which is usually without any path. This options ADDS the path to the
# Makefile.am, and then substracts the 'root' path, to get a SOURCE file
# relative to the 'root' configure.ac, which is what is needed if the DSP
# is to be placed in a $target_dir, and we want the file relative to that
our $add_rel_sources = 1;
our $target_dir = '';
# ==============================================================================
our $ignore_EXTRA_DIST = 0;
our $added_in_init = '';
our $supp_make_in = 0; # Support Makefile.in scanning
our $project_name = ''; # a name to override any ac scanned name of the project

my $dsp_files_skipped = 0;

### =============================
# offsets into REF_LIB_LIST array
our $RLO_MSG = 0;
our $RLO_PRJ = 1;
our $RLO_VAL = 2;
our $RLO_NAM = 3;
our $RLO_EXC = 4;
### =============================

my $write_dsp = 0;
sub get_write_dsp_files() { return $write_dsp; }

sub ac_do_dir_scan($$$) { return; }

sub VERB1() { return $verbosity >= 1; }
sub VERB2() { return $verbosity >= 2; }
sub VERB5() { return $verbosity >= 5; }
sub VERB9() { return $verbosity >= 9; }

sub show_warnings($) {
    my ($val) = @_;
    if (@warnings) {
        prt( "\nGot ".scalar @warnings." WARNINGS...\n" );
        foreach my $itm (@warnings) {
           prt("$itm\n");
        }
        prt("\n");
    } else {
        prt( "\nNo warnings issued.\n\n" ) if (VERB9());
    }
}

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


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


sub process_in_file($);

sub do_substitutions($);


sub do_substitutions($) {
    my $val = shift;
    my $rh = \%subst;
    my @arr = space_split($val);
    my $cnt = scalar @arr;
    my ($i);
    for ($i = 0; $i < $cnt; $i++) {
        $val = $arr[$i];
        if ($val =~ /\$\((.+)\)/) {
            my $tmp = $1;
            if (defined ${$rh}{$tmp}) {
                my $nval = ${$rh}{$tmp};
                $val =~ s/\$\($tmp\)/$nval/;
                $arr[$i] = $val;
            } else {
                if (!defined $subs_not_found{$tmp}) {
                    prtw("WARNING: No sub of [$tmp] in [$val]\n");
                    $subs_not_found{$tmp} = 1;
                }
            }
        }
    }
    return join(" ",@arr);
}

sub is_target_line($$$) {
    my ($line,$rtarg,$ract) = @_;
    if ($line =~ /^(.+):/) {
        my $len = length($line);
        my $targ = '';
        my $act = '';
        my ($i,$ch);
        for ($i = 0; $i < $len; $i++) {
            $ch = substr($line,$i,1);
            last if ($ch eq ':');
            $targ .= $ch;
        }
        $i++;
        for (; $i < $len; $i++) {
            $ch = substr($line,$i,1);
            next if ($ch eq ':');
            $act .= $ch;
        }
        $targ = trim_all($targ);
        $act = trim_all($act);
        ${$rtarg} = $targ;
        ${$ract}  = $act;
        return 1 if (length($targ));
    }
    return 0;
}

sub curr_dep_incs_prev($$) {
    my ($prev,$curr) = @_; # $targets_deps{$targ},$deps
    my @arr1 = space_split($prev);
    my @arr2 = space_split($curr);
    # make sure each item in $prev, is also in $curr
    my ($itm1,$itm2,$fnd);
    foreach $itm1 (@arr1) {
        $itm1 = path_d2u($itm1);
        $fnd = 0;
        foreach $itm2 (@arr2) {
            $itm2 = path_d2u($itm2);
            # path seps are the same - do they compare
            if ($itm1 eq $itm2) {
                $fnd = 1;
                last;
            }
        }
        return 0 if (!$fnd);
    }
    return 1; # all previous found in current = no problem with overwrite
}

sub process_in_file($) {
    my ($inf) = @_;
    if (! open INF, "<$inf") {
        pgm_exit(1,"ERROR: Unable to open file [$inf]\n"); 
    }
    my @lines = <INF>;
    close INF;
    my $lncnt = scalar @lines;
    my $rh = \%subst;
    prt("Processing $lncnt lines, from [$inf]...\n");
    my ($line,$inc,$lnn,$i,$tline,$len,$i2,$tmp,$blnn,$elnn,$ff);
    my ($key,$val,$targ,$act,$tmp2,$deps);
    my ($name,$dir) = fileparse($inf);
    ut_fix_directory(\$dir);
    $lnn = 0;
    my $inif = 0;
    my @ifstack = ();
    for ($i = 0; $i < $lncnt; $i++) {
        $line = $lines[$i];
        chomp $line;
        $lnn++;
        $i2 = $i + 1;
        $tline = trim_all($line);
        $len = length($tline);
        next if ($len == 0);
        next if ($tline =~ /^\#/);
        $blnn = $lnn;
        while (($i2 < $lncnt) && ($tline =~ /\\$/)) {
            $tline =~ s/\\$//;  # remove trailing '\'
            $i++;
            $tmp = $lines[$i];  # get next
            chomp $tmp;
            $lnn++;
            $i2 = $i + 1;
            $tline .= ' '.trim_all($tmp);
        }
        $elnn = $lnn;
        $tline = trim_all($tline);
        $len = length($tline);
        prt("$blnn-$elnn: $len [$tline]\n") if (VERB9());
        if ($tline =~ /^!/) {
            # [!INCLUDE ../boostregex/nppSpecifics.mak]
            if ($tline =~ /^!INCLUDE\s+(.+)$/i) {
                $inc = $1;
                $ff = File::Spec->rel2abs($dir.$inc);
                if (-f $ff) {
                    process_in_file($ff);
                } else {
                    prtw("WARNING: Unable to find INCLUDE [$ff] [$inc]!\n");
                }
            } elsif ($tline =~ /^!IF\s+(.+)$/i) {
                $inc = $1;
                push(@ifstack,"\@".$inc."_TRUE\@");
                $inif++;
            } elsif ($tline =~ /^!IFDEF\s(.+)$/i) {
                $inc = $1;
        		###if (! $configure_cond{$1});
	            ###push (@conditional_stack, "\@" . $1 . "_TRUE\@");
                push(@ifstack,"\@".$inc."_TRUE\@");
                $inif++;
            } elsif ($tline =~ /^!ELSE\b/i) {
                if (@ifstack) {
                    $inc = $ifstack[$#ifstack]; # get last
                    if ($inc =~ /_FALSE\@$/) {
                        prtw("WARNING:$blnn-$elnn: ELSE after ELSE! [$inc] [$tline]\n file [$inf]\n");
                    } else {
                        $inc =~  s/_TRUE\@$/_FALSE\@/;
                        $ifstack[$#ifstack] = $inc;
                    }

                } else {
                    prtw("WARNING:$blnn-$elnn: ELSE with NO IF! [$tline]\n file [$inf]\n");
                }
            } elsif ($tline =~ /^!ENDIF\b/i) {
                if (@ifstack) {
                    pop @ifstack;
                } else {
                    prtw("WARNING:$blnn-$elnn: ENDIF with NO IF! [$tline]\n file [$inf]\n");
                }
                $inif-- if ($inif);
            } elsif ($tline =~ /^!MESSAGE\b(.*)$/i) {
            } elsif ($tline =~ /^!ERROR\s+(.+)$/i) {
            } else {
                prtw("WARNING:$blnn-$elnn: Uncased ! command [$tline] FIX ME!\n file [$inf]\n");
            }
        } else {
            ###if ($tline =~ /^(\w+)\s*=\s*(.+)$/) - can be a blank
            if ($tline =~ /^(\w+)\s*=\s*(.*)$/) {
                $key = $1;
                $tmp = $2;
                $val = do_substitutions($tmp);
                if (defined ${$rh}{$key} ) {
                    ${$rh}{$key} .= " $val";
                    prt("$blnn-$elnn: Add key [$key] = value [$val]\n") if (VERB5());
                } else {
                    ${$rh}{$key} = $val;
                    prt("$blnn-$elnn: Set key [$key] = value [$val]\n") if (VERB5());
                }
            } elsif ($tline =~ /^(\w+)\s*:/) {
                $targ = $1;
                $act = '';
                $deps = '';
                if ($tline =~ /^\w+\s*:\s*(.+)$/) {
                    $deps = $1;
                }
                # must collect following actions
                while ($i2 < $lncnt) {
                    $i++;
                    $i2 = $i + 1;
                    $tmp = $lines[$i];
                    next if ($tmp =~ /^\#/);
                    if ($tmp =~ /^\S/) {    # should commence with TAB - here just non-space
                        $i--;   # back up to process this line later
                        last;
                    }
                    $lnn++;
                    chomp $tmp;
                    $tmp = trim_all($tmp);
                    $len = length($tmp);
                    last if ($len == 0);    # no need to back up - is a blank line - skip it
                    while (($i2 < $lncnt) && ($tmp =~ /\\$/)) {
                        $tmp =~ s/\\$//;  # remove trailing '\'
                        $i++;
                        $tmp2 = $lines[$i];  # get next
                        chomp $tmp2;
                        $lnn++;
                        $i2 = $i + 1;
                        $tmp .= ' '.trim_all($tmp2);
                    }
                    $act .= ' | ' if (length($act));
                    $act .= $tmp;
                }
                $elnn = $lnn;
                $act = do_substitutions($act);
                $deps = do_substitutions($deps);
                prt("$blnn-$elnn: TARGET [$targ] deps [$deps]\n actions [$act]\n"); # if (VERB5());
                if ((defined $targets_deps{$targ}) && ($targets_deps{$targ} ne $deps)){
                    prtw("WARNING: TARGET [$targ] deps [".$targets_deps{$targ}."] being over written\n by [$deps]\n");
                }
                $targets_deps{$targ} = $deps;
                $targets_acts{$targ} = $act;
                $targets_file{$targ} = $inf;
            } elsif ($tline =~ /^\.SUFFIXES\s*:\s*(.+)$/) {
                # [.SUFFIXES: cxx]
            } else {
                $line = do_substitutions($tline);
                $act = '';
                $deps = '';
                if (is_target_line($line,\$targ,\$deps)) {
                   # must collect following actions
                    while ($i2 < $lncnt) {
                        $i++;
                        $i2 = $i + 1;
                        $tmp = $lines[$i];
                        next if ($tmp =~ /^\#/);
                        if ($tmp =~ /^\S/) {   # line does NOT commence with tab (here a non-space)
                            $i--; # back up to process this line
                            last;
                        }
                        chomp $tmp;
                        $lnn++;
                        $tmp = trim_all($tmp);
                        $len = length($tmp);
                        last if ($len == 0);
                        while (($i2 < $lncnt) && ($tmp =~ /\\$/)) {
                            $tmp =~ s/\\$//;  # remove trailing '\'
                            $i++;
                            $tmp2 = $lines[$i];  # get next
                            chomp $tmp2;
                            $lnn++;
                            $i2 = $i + 1;
                            $tmp .= ' '.trim_all($tmp2);
                        }
                        $act .= ' | ' if (length($act));
                        $act .= $tmp;
                    }
                    $elnn = $lnn;
                    $act = do_substitutions($act);
                    $deps = do_substitutions($deps);
                    prt("$blnn-$elnn: Target [$targ] deps [$deps]\n actions [$act]\n"); # if (VERB5());
                    if ((defined $targets_deps{$targ}) && ($targets_deps{$targ} ne $deps) && !curr_dep_incs_prev($targets_deps{$targ},$deps)){
                        prtw("WARNING: Target [$targ] deps [".$targets_deps{$targ}."] being over written\nwith [$deps]");
                    }
                    $targets_deps{$targ} = $deps;
                    $targets_acts{$targ} = $act;
                    $targets_file{$targ} = $inf;
                } else {
                    prtw("WARNING:$blnn-$elnn: Line NOT delt with [$line]\n file [$inf]\n");
                }
            }
        }
    }
    prt("Done $lncnt lines, from [$inf]...\n");
    if (@ifstack) {
        $tmp = scalar @ifstack;
        $inc = join(" ",@ifstack);
        prtw("WARNING: Exit file with $tmp items on IF-STACK!\n $inc\n");
    }
}

my %dhashes = ();

sub get_directory_hash($) {
    my $dir = shift;
    if (defined $dhashes{$dir}) {
        return $dhashes{$dir};
    }
    my %h = ();
    if (! opendir(DIR, $dir)) {
        return \%h;
    }
    my @files = readdir(DIR);
    closedir(DIR);
    my ($file,$n,$d,$e,$ra);
    foreach $file (@files) {
        next if ($file eq '.');
        next if ($file eq '..');
        ($n,$d,$e) = fileparse($file, qr/\.[^.]*/);
        $h{$n} = [] if (!defined $h{$n});
        $ra = $h{$n};
        push(@{$ra},$e);
    }
    $dhashes{$dir} = \%h;
    return \%h;
}

#                    $ff = File::Spec->rel2abs($fdir.$fil);
#                    ($n,$d,$e) = fileparse($ff, qr/\.[^.]*/);
#                    $rdh = get_directory_hash($d);
#                    if (defined ${$rdh}{$n}) {
#                        $ext = '.???';
#                        $ok = "NF";
#                        $ra = ${$rdh}{$n}; # get array of extensions
#                        $ecnt = scalar @{$ra};
#                        if ($ecnt == 1) {
#                            # only ONE choice - choose it
#                            $ext = ${$ra}[0];
#                        } else {
#                            # multiple choices - choose extended c source
#                            $ext = '';
#                            foreach $e (@{$ra}) {
#                                $ff = $n.$e;
#                                if (is_c_source_extended($ff)) {
#                                    $ext = $e;
#                                    last;
#                                }
#                            }
#                        }
#                        $ff = $d.$n.$ext;
#                        $ok = 'ok' if (-f $ff);
#                        prt(" $cnt2: $ff $ok\n");
#                    } else {
#                        prt(" $cnt2: [$fil] [$ff] NOT FOUND\n");
#                    }

# 50-51: TARGET [ALL] deps [..\bin\Scintilla.dll ..\bin\SciLexer.dll Lexers.lib .\ScintillaWinS.obj]
# my $app_console_stg  = 'Console Application';
# my $app_windows_stg  = 'Application';
# my $app_dynalib_stg  = 'Dynamic-Link Library';
# my $app_statlib_stg  = 'Static Library';
# my $app_utility_stg  = 'Utility';
sub get_type_from_key($) {
    my $key = shift;
    my $type = "Unknown";
    if ($key =~ /\.dll$/i) {
        $type = 'Dynamic-Link Library';
    } elsif ($key =~ /\.lib$/i) {
        $type = 'Static Library';
    } elsif ($key =~ /\.obj$/i) {
        $type = 'Static Library';   # not sure about this
    } elsif ($key =~ /\.exe$/i) {
        $type = 'Application';  # how to know if this or 'Console Application'
    } else {
        pgm_exit(1,"ERROR: Key [$key] NOT TYPED! FIX ME!\n");
    }
    return $type;
}

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

sub sort_target_deps() {
    my $rh = \%targets_deps;
    my $rhf = \%targets_file;

    my @arr = keys(%{$rh});
    my $cnt = scalar @arr;
    my ($key,$val,$fil);
    my ($fname,$fdir,$rdh);
    my ($n,$d,$e);
    my ($ff,@arr2,$cnt2,$ra,$ecnt,$ext);
    my ($ok);
    my ($val2,$fil2);
    my ($fil3,@arr3,$cnt3);
    my ($type,$rp,$proj_name);
    my $all_key = '';
    my $all_dep = '';
    foreach $key (@arr) {
        $val = ${$rh}{$key};
        if ($key =~ /^all$/i) {
            $all_key = $key;
            $all_dep = $val;
        }
    }
    my %not_found = ();
    my %my_src_hash = ();
    my $rsh = \%my_src_hash;
    my %projects_hash = ();
    my $rph = \%projects_hash;
    if (length($all_key)) {
        # 50-51: TARGET [ALL] deps [..\bin\Scintilla.dll ..\bin\SciLexer.dll Lexers.lib .\ScintillaWinS.obj]
        prt("\nIn $cnt targets, found 'all:' with deps [$all_dep]\n");
        @arr = space_split($all_dep);   # all: dependency list - ie targets to process
        $cnt = 0;
        # 1: [..\bin\Scintilla.dll] deps [.\AutoComplete.obj .\CallTip.obj .\CellBuffer.obj .\CharacterSet.obj .\CharClassify.obj .\ContractionState.obj .\Decoration.obj .\Document.obj .\Editor.obj .\Indicator.obj .\KeyMap.obj .\LineMarker.obj .\PerLine.obj .\PlatWin.obj .\PositionCache.obj .\PropSetSimple.obj .\RESearch.obj .\RunStyles.obj .\ScintillaBase.obj .\ScintillaWin.obj .\Selection.obj .\Style.obj .\UniConversion.obj .\ViewStyle.obj .\XPM.obj .\AutoComplete.obj .\CallTip.obj .\CellBuffer.obj .\CharacterSet.obj .\CharClassify.obj .\ContractionState.obj .\Decoration.obj .\Document.obj .\Editor.obj .\Indicator.obj .\KeyMap.obj .\LineMarker.obj .\PerLine.obj .\PlatWin.obj .\PositionCache.obj .\PropSetSimple.obj .\RESearch.obj .\RunStyles.obj .\ScintillaBase.obj .\ScintillaWin.obj .\Selection.obj .\Style.obj .\UniConversion.obj .\ViewStyle.obj .\XPM.obj .\BoostRegexSearch.obj .\UTF8DocumentIterator.obj .\ScintRes.res]
        #   1: [.\AutoComplete.obj] [C:\Projects\notepad-plus\scintilla\win32\AutoComplete.obj] NOT FOUND
        foreach $key (@arr) {
            $cnt++;
            $type = get_type_from_key($key);
            $rp = get_anon_proj_hash();
            ($proj_name,$d,$e) = fileparse($key, qr/\.[^.]*/);
            ${$rp}{'PROJECT_TYPE'} = $type;
    		${$rp}{'PROJECT_KEY'} = $key;
            ${$rp}{'PROJECT_NAME'} = $proj_name; # != $key
            $val = "Target NOT FOUND";
            my @c_files = ();
            my @h_files = ();
            my @srcs = ();
            my %dupes = ();
            if (defined ${$rh}{$key}) {
                $val = ${$rh}{$key};
                $fil = ${$rhf}{$key};
                ($fname,$fdir) = fileparse($fil);
                $ff = File::Spec->rel2abs($fdir.$key);
                @arr2 = space_split($val);
                $cnt2 = scalar @arr2;
                prt("$cnt: [$key] deps $cnt2 [$val]\n");
                # 251-252: Target [.\AutoComplete.obj] deps [../src/AutoComplete.cxx ../include/Platform.h ../src/AutoComplete.h]
                # 241-243: Target [.\ScintillaWinS.obj] deps [ScintillaWin.cxx]
                $cnt2 = 0;
                foreach $fil (@arr2) {
                    $cnt2++;
                    $ff = File::Spec->rel2abs($fdir.$fil);
                    $ok = "TARGET NOT FOUND!";
                    if (defined ${$rh}{$fil}) {
                        $val2 = ${$rh}{$fil}; # this could/should be the sources for this target
                        $fil2 = ${$rhf}{$fil}; # and the source makefile it was in...
                        ($fname,$fdir) = fileparse($fil2);
                        @arr3 = space_split($val2);
                        $cnt3 = 0;
                        foreach $fil3 (@arr3) {
                            $cnt3++;
                            $ff = File::Spec->rel2abs($fdir.$fil3);
                            $ok = (-f $ff) ? "ok" : "NF";
                            prt(" $cnt2:$cnt3: targ [$fil] source $ff $ok\n");
                            if (defined $dupes{$ff}) {
                                if (is_c_source($fil3)) {
                                    prtw("WARNING:$proj_name: Duplicate SOURCE of [$ff] avoided!\n");
                                } elsif (is_h_source($fil3)) {
                                    prtw("WARNING:$proj_name: Duplicate HEADER of [$ff] avoided!\n") if (VERB9());
                                }
                            } else {
                                if (is_c_source($fil3)) {
                                    push(@c_files,$ff);
                                } elsif (is_h_source($fil3)) {
                                    push(@h_files,$ff);
                                }
                                push(@srcs,$ff);
                                $dupes{$ff} = 1;
                            }
                        }
                    } elsif (is_c_source_extended($fil) && (-f $ff)) {
                        # this is the SOURCE
                        prt(" $cnt2:$cnt3: C/C++ src [$fil] [$ff] OK\n");
                        if (defined $dupes{$ff}) {
                            prtw("WARNING:$proj_name: Duplicate source name of [$ff] avoided!\n");
                        } else {
                            push(@c_files,$ff);
                            push(@srcs,$ff);
                            $dupes{$ff} = 1;
                        }
                    } elsif (is_h_source($fil) && (-f $ff)) {
                        prt(" $cnt2:$cnt3: HEADER file [$fil] [$ff] OK\n");
                        if (defined $dupes{$ff}) {
                            prtw("WARNING:$proj_name: Duplicate header of [$ff] avoided!\n") if (VERB9());
                        } else {
                            push(@h_files,$ff);
                            push(@srcs,$ff);
                            $dupes{$ff} = 1;
                        }
                    } elsif (($fil =~ /\.rc$/i) && (-f $ff)) {
                        prt(" $cnt2:$cnt3: RES file [$fil] [$ff] OK\n");
                        if (defined $dupes{$ff}) {
                            prtw("WARNING:$proj_name: Duplicate RES of [$ff] avoided!\n");
                        } else {
                            push(@srcs,$ff);
                            $dupes{$ff} = 1;
                        }
                    } elsif (-f $ff) {
                        prt(" $cnt2:$cnt3: OTHER file [$fil] [$ff] OK\n");
                        if (defined $dupes{$ff}) {
                            prtw("WARNING:$proj_name: Duplicate OTHER of [$ff] avoided!\n");
                        } else {
                            push(@srcs,$ff);
                            $dupes{$ff} = 1;
                        }
                    } else {
                        if (!defined $not_found{$fil}) {
                            $not_found{$fil} = 1;
                            prtw("WARNING:$cnt2: targ [$fil] $ok\n");
                        }
                    }
                }
                ${$rp}{'PROJECT_SOURCES'} = \@srcs;  # source
                ${$rph}{$proj_name} = $rp;
                ${$rsh}{$proj_name} = \@srcs;
            } else {
                if (!defined $not_found{$key}) {
                    $not_found{$key} = 1;
                    prtw("WARNING:$cnt: [$key] deps [$val]\n");
                }
            }
        }
    } else {
        prt("In $cnt targets, NO find of 'all:'!\n");
    }
    ${$rparams}{'REF_SOURCES_HASH'} = $rsh;  # store sources/proj_name hash
    ${$rparams}{'REF_PROJECTS_HASH'} = $rph; # store projects/proj_name hash
}


#########################################
### MAIN ###
parse_args(@ARGV);
process_in_file($in_file);
sort_target_deps();
pgm_exit(0,"");
########################################

sub need_arg {
    my ($arg,@av) = @_;
    pgm_exit(1,"ERROR: [$arg] must have a following argument!\n") if (!@av);
}

sub parse_args {
    my (@av) = @_;
    my ($arg,$sarg);
    my $got_par = 0;
    while (@av) {
        $arg = $av[0];
        if ($arg =~ /^-/) {
            $sarg = substr($arg,1);
            $sarg = substr($sarg,1) while ($sarg =~ /^-/);
            if (($sarg =~ /^h/i)||($sarg eq '?')) {
                give_help();
                pgm_exit(0,"Help exit(0)");
            } elsif ($sarg =~ /^v/) {
                if ($sarg =~ /^v.*(\d+)$/) {
                    $verbosity = $1;
                } else {
                    while ($sarg =~ /^v/) {
                        $verbosity++;
                        $sarg = substr($sarg,1);
                    }
                }
                prt("Verbosity = $verbosity\n") if (VERB1());
            } elsif ($sarg =~ /^l/) {
                if ($sarg =~ /^ll/) {
                    $load_log = 2;
                } else {
                    $load_log = 1;
                }
                prt("Set to load log at end. ($load_log)\n") if (VERB1());
            } elsif ($sarg =~ /^o/) {
                need_arg(@av);
                shift @av;
                $sarg = $av[0];
                $out_file = $sarg;
                prt("Set out file to [$out_file].\n") if (VERB1());
            } else {
                pgm_exit(1,"ERROR: Invalid argument [$arg]! Try -?\n");
            }
        } else {
            $in_file = File::Spec->rel2abs($arg);
            prt("Set input to [$in_file]\n") if (VERB1());

        }
        shift @av;
    }

    if ((length($in_file) ==  0) && $debug_on) {
        $in_file = File::Spec->rel2abs($def_file);
        prt("Set DEFAULT input to [$in_file]\n");
        $load_log = 2;
    }
    if (length($in_file) ==  0) {
        pgm_exit(1,"ERROR: No input files found in command!\n");
    }
    if (! -f $in_file) {
        pgm_exit(1,"ERROR: Unable to find in file [$in_file]! Check name, location...\n");
    }
    $rparams = init_common_subs($in_file) if (!$got_par); # note: sets ROOT_FOLDER - where a CMakeLists.txt could be written
}

sub give_help {
    prt("$pgmname: version $VERS\n");
    prt("Usage: $pgmname [options] in-file\n");
    prt("Options:\n");
    prt(" --help  (-h or -?) = This help, and exit 0.\n");
    prt(" --verb[n]     (-v) = Bump [or set] verbosity. def=$verbosity\n");
    prt(" --load        (-l) = Load LOG at end. ($outfile)\n");
    prt(" --out <file>  (-o) = Write output to this file.\n");
}

# eof - template.pl
