#!/usr/bin/perl -w # NAME: nsisfiles.pl # AIM: Read a MSIS msi script, and prepare a file list... # 15/02/2013 - Initial cut use strict; use warnings; use File::Basename; # split path ($name,$dir,$ext) = fileparse($file [, qr/\.[^.]*/] ) use File::stat; # get file info if ($sb = stat($fil)){$dt = $sb->mtime; $sz = $sb->size;} 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_vcdirs.pl' or die "Unable to load 'lib_vcdirs.pl' Check paths in \@INC...\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 = ''; my $nsis_dir = ''; my $add_inst_dir = 0; my $do_expand_wild = 1; # ### DEBUG ### my $debug_on = 1; my $def_file = 'C:\FG\17\build-install\fgx-fgfs-2.10.0-vs2010.nsi'; my $def_nsis = 'C:\Program Files (x86)\NSIS'; my $def_out = $temp_dir.$PATH_SEP."tempfl.txt"; my $def_fgvers = '2.10.0'; my $def_osgver = '3.1.4'; my $def_osgnum = '93'; ### program variables my @warnings = (); my $cwd = cwd(); 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 strip_comments($) { my $line = shift; $line =~ s/(.+);.*$/$1/; $line =~ s/(.+)\#.*$/$1/; $line = trim_all($line); return $line; } my %macro_subs = (); my %done_files = (); sub process_in_file($); sub got_wild($) { my $txt = shift; if ($txt =~ /\*/) { return 1; } elsif ($txt =~ /\?/) { return 2; } return 0; } sub expand_wild($$) { my ($ra,$wild) = @_; # \@out_files,$tmp); my (@files,$file,$ff); my %hash = (); if ($wild =~ /\s+/) { $wild =~ s/\\\\/\\/g; my ($nm,$dir) = fileparse($wild); if ((-d $dir)&&(opendir(DIR,$dir))) { @files = readdir(DIR); closedir(DIR); foreach $file (@files) { next if ($file eq '.'); next if ($file eq '..'); $ff = $dir.$file; if (-f $ff) { push(@{$ra},$ff); } } } else { push(@{$ra},$wild); # glob does NOT seem to handle spaces well } } else { @files = glob($wild); if (@files) { foreach $file (@files) { $hash{$file} = 1; } foreach $file (@files) { #if (-f $file) { push(@{$ra},$file); #} } } else { push(@{$ra},$wild); } } } sub do_any_subs($) { my $rtxt = shift; my $txt = ${$rtxt}; my $len = length($txt); my $ntxt = ''; my ($tmp,$i,$ch,$pc,$tag,$i2,$nc,$bal,$j,$nxt,$len2); my $tst = ''; my $cnt = 0; $pc = 0; for ($i = 0; $i < $len; $i++) { $ch = substr($txt,$i,1); $tst .= $ch if ($ch ne '"'); } $txt = $tst; $len = length($txt); $tst = ''; for ($i = 0; $i < $len; $i++) { $ch = substr($txt,$i,1); $i2 = $i + 1; $nc = ($i2 < $len) ? substr($txt,$i2,1) : ''; $i2++; if (($ch eq '$')&&($nc eq '{')&&($i2 < $len)) { $bal = substr($txt,$i2); $len2 = length($bal); $pc = 1; $tag = ''; $nxt = 0; for ($j = 0; $j < $len2; $j++) { $nc = substr($bal,$j,1); $nxt = $j; if ($nc eq '{') { $pc++; $tag .= $nc; } elsif ($nc eq '}') { $pc--; if ($pc == 0) { last; } else { $tag .= $nc; } } else { $tag .= $nc; } } if ($pc == 0) { if (defined $macro_subs{$tag}) { $tmp = $macro_subs{$tag}; prt("Sub [$tag] with [$tmp] in [\${$bal]\n") if (VERB9()); $ntxt .= $tmp; $cnt++; $i = $i2 + $nxt; } else { $ntxt .= $ch; } } else { $ntxt .= $ch; } } elsif ( ($ch eq '$') && ($i2 < $len) ) { $i2--; $bal = substr($txt,$i2); $len2 = length($bal); if ( (defined $macro_subs{'INSTDIR'}) && ($bal =~ /^INSTDIR/) ) { #$bal = substr($bal,7); $ntxt = $macro_subs{'INSTDIR'}; $i += 7; } elsif ( (defined $macro_subs{'LOCALAPPDATA'}) && ($bal =~ /^LOCALAPPDATA/) ) { $ntxt = $macro_subs{'LOCALAPPDATA'}; $i += 12; } elsif ( (defined $macro_subs{'VCINSTALLDIR'}) && ($bal =~ /^\%VCINSTALLDIR\%/) ) { $ntxt = $macro_subs{'VCINSTALLDIR'}; $i += 14; } else { $ntxt .= $ch; } } else { $ntxt .= $ch; } } $txt = ${$rtxt}; ${$rtxt} = $ntxt; return $cnt; } # skip QUOTED by either if (($ch eq '"')||($ch eq "'")||($ch eq "`")) { sub space_split3 { my ($txt) = shift; my $len = length($txt); my ($k,$ch,$tag,$incomm,$k2,$nch,$pc,$cc); my @arr = (); $tag = ''; $incomm = 0; $ch = ''; $cc = ''; for ($k = 0; $k < $len; $k++) { $ch = substr($txt,$k,1); $k2 = $k + 1; $nch = ($k2 < $len) ? substr($txt,$k2,1) : ""; if ($incomm) { $incomm = 0 if ($ch eq $cc); $tag .= $ch; # add 2010/05/05 to avoid say '"zlib">' begin a tag if (!$incomm) { push(@arr,$tag); $tag = ''; } } elsif ($ch =~ /\s/) { # any spacey char push(@arr, $tag) if (length($tag)); $tag = ''; } elsif (($ch =~ /\//)&&($nch eq '>')) { # 04/10/2008, but only if before '>' 24/09/2008 add this as well push(@arr, $tag) if (length($tag)); $tag = $ch; # restart tag with this character } else { $tag .= $ch; if (($ch eq '"')||($ch eq "'")||($ch eq "`")) { $incomm = 1; $cc = $ch; } } } push(@arr, $tag) if (length($tag)); return @arr; } my $file_counter = 0; my @out_files = (); sub process_in_file($) { my ($inf) = @_; return if (defined $done_files{$inf}); $done_files{$inf} = 1; if (! open INF, "<$inf") { pgm_exit(1,"ERROR: Unable to open file [$inf]\n"); } my @lines = ; close INF; my $lncnt = scalar @lines; prt("Processing $lncnt lines, from [$inf]...\n"); # if (VERB5()); $file_counter++; my ($line,$inc,$lnn,$ff1,$ff2,$ff3,$oinc); my ($command,$remain,$i,$len,$inmac,@arr,$tmp); my ($acnt,$def,$j); my ($nm,$dir) = fileparse($inf); my $ndir = $nsis_dir; my $out_path = ''; ut_fix_directory(\$dir); if (-d $ndir) { if (!defined $macro_subs{'NSISDIR'}) { $macro_subs{'NSISDIR'} = $ndir; prt("Added macro NSISDIR => $ndir\n"); } ut_fix_directory(\$ndir); $ndir .= "Include".$PATH_SEP; } $lnn = 0; $inmac = 0; for ($i = 0; $i < $lncnt; $i++) { $line = $lines[$i]; chomp $line; $lnn++; # skip comments next if ($line =~ /^\s*;/); next if ($line =~ /^\s*\#/); $line = trim_all($line); $len = length($line); next if ($len == 0); if ($line =~ /^\/\*/) { # comment begin #$line = s/^\/\*//; $line = substr($line,2); while ( !($line =~ /\*\//) ) { $i++; if ($i < $lncnt) { $line = $lines[$i]; chomp $line; $lnn++; $line = trim_all($line); } else { prt("Done IN COMMENT $lncnt lines, from [$inf]...\n"); return; } } next; } $line = strip_comments($line); @arr = space_split3($line); $acnt = scalar @arr; $tmp = ''; for ($j = 1; $j < $acnt; $j++) { $tmp .= ' ' if (length($tmp)); $tmp .= $arr[$j]; } do_any_subs(\$tmp); if ($line =~ /!\s*include\s+(.+)$/) { $oinc = strip_both_quotes($1); $inc = $oinc; prt("$lnn: include $inc\n"); if (do_any_subs(\$inc)) { prt("$lnn: INCLUDE $inc\n"); } $ff1 = $dir.$inc; $ff2 = $ndir.$inc; $ff3 = $inc; if (-f $ff1) { process_in_file($ff1); } elsif (-f $ff2) { process_in_file($ff2); } elsif (-f $ff3) { process_in_file($ff3); } else { if ($inmac) { prt("Unable to locate INCLUDE FILE in MACRO!\n"); } else { prt("Unable to locate INCLUDE FILE!\n". "Not [$ff1], \nnor [$ff2], \nnor [$ff3]!\n"); } } } elsif ($line =~ /^!(\w+)\s+(.+)$/) { $command = $1; $remain = $2; if ($command eq 'system') { } elsif ($command eq 'define') { @arr = space_split3($remain); $def = $arr[0]; $acnt = scalar @arr; if ($def eq '/math') { prt("$lnn: MATH [$remain]\n") if (VERB9()); } elsif ($def eq '/file') { prt("$lnn: FILE [$remain]\n") if (VERB9()); } elsif ($acnt == 1) { $macro_subs{$def} = 'NULL'; prt("$lnn:1: $command $def NULL\n") if (VERB9()); } elsif ($acnt == 2) { $tmp = strip_both_quotes($arr[1]); do_any_subs(\$tmp); $macro_subs{$def} = $tmp; prt("$lnn:2: $command $def = $tmp\n") if (VERB9()); } else { pgm_exit(1,"$lnn:$acnt: [$line] NOT HANDLED! FIX ME!\n"); } } elsif ($command eq 'echo') { } elsif ($command eq 'if') { } elsif ($command eq 'ifndef') { } elsif ($command eq 'ifdef') { } elsif ($command eq 'else') { } elsif ($command eq 'undef') { } elsif ($command eq 'error') { } elsif ($command eq 'verbose') { } elsif ($command eq 'macro') { $inmac = 1; } elsif ($command eq 'insertmacro') { } elsif ($command eq 'addincludedir') { } elsif ($command eq 'appendfile') { } elsif ($command eq 'delfile') { } elsif ($command eq 'tempfile') { } else { pgm_exit(1,"$lnn: Unparsed line [$line]! FIX ME\n"); } } elsif ($line =~ /^!(\w+)\s*$/) { $command = $1; if ($command eq 'macroend') { $inmac = 0; } elsif ($command eq 'else') { } elsif ($command eq 'endif') { } else { pgm_exit(1,"$lnn: Unparsed command [$line]! FIX ME\n"); } } elsif ($line =~ /^Var/) { } elsif ($line =~ /^Goto/) { } elsif ($line =~ /^Push/) { } elsif ($line =~ /^Pop/) { } elsif ($line =~ /^StrCpy/) { } elsif ($line =~ /^StrCmp/) { } elsif ($line =~ /^IntOp/) { } elsif ($line =~ /^IntCmp/) { } elsif ($line =~ /^SectionGetFlags/) { } elsif ($line =~ /^SectionSetFlags/) { } elsif ($line =~ /^SectionGetInstTypes/) { } elsif ($line =~ /^SectionSetInstTypes/) { } elsif ($line =~ /^System::/) { } elsif ($line =~ /^Function/) { } elsif ($line =~ /^Exch/) { } elsif ($line =~ /^Call/) { } elsif ($line =~ /^If/) { #} elsif ($line =~ /^IfAbort/) { #} elsif ($line =~ /^IfErrors/) { #} elsif ($line =~ /^IfFileExist/) { } elsif ($line =~ /^\$\{.+\}/) { } elsif ($line =~ /^GetFunctionAddress/) { } elsif ($line =~ /^nsDialogs/) { } elsif ($line =~ /^SendMessage/) { } elsif ($line =~ /^ReadINIStr/) { } elsif ($line =~ /^WriteINIStr/) { } elsif ($line =~ /^ExecShell/) { } elsif ($line =~ /^LangString/) { } elsif ($line =~ /^XPStyle/) { } elsif ($line =~ /^ChangeUI/) { } elsif ($line =~ /^Icon/) { } elsif ($line =~ /^UninstallIcon/) { } elsif ($line =~ /^MessageBox/) { } elsif ($line =~ /^Abort/) { } elsif ($line =~ /^mui/) { } elsif ($line =~ /^InitPluginsDir/) { } elsif ($line =~ /^File/) { prt("Load FILE [$tmp]\n") if (VERB5()); if ($tmp =~ /^\/oname=/) { # /oname=$PLUGINSDIR\modern-wizard.bmp ${MUI_${MUI_PAGE_UNINSTALLER_PREFIX}WELCOMEFINISHPAGE_BITMAP} # not handled } else { if ($do_expand_wild && got_wild($tmp)) { expand_wild(\@out_files,$tmp); } else { push(@out_files,$tmp); } } } elsif ($line =~ /^SetOutPath/) { # where ot put the file prt("Out PATH [$tmp]\n") if (VERB5()); $out_path = $tmp; push(@out_files,"OUTDIR=$tmp"); } elsif ($line =~ /^SetBrandingImage/) { } elsif ($line =~ /^GetDlgItem/) { } elsif ($line =~ /^CreateFont/) { } elsif ($line =~ /^SetCtlColors/) { } elsif ($line =~ /^LoadLanguageFile/) { } elsif ($line =~ /^ReadRegStr/) { } elsif ($line =~ /^WriteRegStr/) { } elsif ($line =~ /^WriteRegDWORD/) { } elsif ($line =~ /^LangDLL/) { } elsif ($line =~ /^ReserveFile/) { } elsif ($line =~ /^LockWindow/) { } elsif ($line =~ /^ShowWindow/) { } elsif ($line =~ /^FindWindow/) { } elsif ($line =~ /^EnableWindow/) { } elsif ($line =~ /^CheckBitmap/) { } elsif ($line =~ /^PageEx/) { } elsif ($line =~ /^PageCallbacks/) { } elsif ($line =~ /^Caption/) { } elsif ($line =~ /^ComponentText/) { } elsif ($line =~ /^DirText/) { } elsif ($line =~ /^DirVar/) { } elsif ($line =~ /^DirVerify/) { } elsif ($line =~ /^SetAutoClose/) { } elsif ($line =~ /^Quit/) { } elsif ($line =~ /^Reboot/) { } elsif ($line =~ /^Return/) { } elsif ($line =~ /^Exec/) { } elsif ($line =~ /^InstallColors/) { } elsif ($line =~ /^InstProgressFlags/) { } elsif ($line =~ /^SubCaption/) { } elsif ($line =~ /^UninstallSubCaption/) { } elsif ($line =~ /^License/) { #} elsif ($line =~ /^LicenseBkColor/) { #} elsif ($line =~ /^LicenseData/) { #} elsif ($line =~ /^LicenseText/) { } elsif ($line =~ /^ClearErrors/) { } elsif ($line =~ /^StartMenu/) { } elsif ($line =~ /^Uninstall/) { } elsif ($line =~ /^Name/) { } elsif ($line =~ /^OutFile/) { } elsif ($line =~ /^SetCompressor/) { } elsif ($line =~ /^RequestExecutionLevel/) { } elsif ($line =~ /^InstallDir/) { push(@out_files,"INSTDIR=$tmp"); prt("Set INSTDIR=$tmp\n"); if (!defined $macro_subs{'INSTDIR'}) { if ($add_inst_dir) { $macro_subs{'INSTDIR'} = $tmp; } } } elsif ($line =~ /^Section/) { } elsif ($line =~ /^SetShellVarContext/) { } elsif ($line =~ /^CreateShortCut/) { } elsif ($line =~ /^CreateDirectory/) { } elsif ($line =~ /^WriteUninstaller/) { } elsif ($line =~ /^Delete/) { } elsif ($line =~ /^RMDir/) { } else { prt("Unparsed line [$line]! FIX ME\n"); pgm_exit(1,"$lnn: in [$inf] FIX ME\n"); } } prt("Done $lncnt lines, from [$inf]...\n"); $file_counter-- if ($file_counter); if ($file_counter == 0) { my ($sb,$sz,$total_size); $total_size = 0; $acnt = scalar @out_files; if (length($out_file) == 0) { prt("Loaded $acnt files... no out file (-o file) given...\n"); } else { $line = ''; foreach $tmp (@out_files) { $line .= "$tmp\n"; if ($sb = stat($tmp)) { $sz = $sb->size; $total_size += $sz; } } write2file($line,$out_file); prt("Loaded $acnt files... written to file [$out_file]\n"); prt("Estimated total size ".get_nn($total_size)." bytes. (".util_bytes2ks($total_size).")\n"); } } } sub set_up() { if (exists $ENV{'LOCALAPPDATA'}) { $macro_subs{'LOCALAPPDATA'} = $ENV{'LOCALAPPDATA'}; } my ($instdir); if (get_vcinstalldir(\$instdir)) { prt("Got VCINSTALLDIR=$instdir\n"); $macro_subs{'VCINSTALLDIR'} = $instdir; } else { prt("FAILED to get VCINSTALLDIR dirs\n"); } } sub test() { my ($incdirs,$instdir); if (get_vsinstalldir(\$instdir)) { prt("Got VCINSTALLDIR=$instdir\n"); } else { prt("FAILED to get VCINSTALLDIR dirs\n"); } prt("Getting INCLUDE directories...\n"); if (get_include_dirs3(\$incdirs)) { my $cnt = scalar @{$incdirs}; prt("Got $cnt inc dirs\n"); foreach $cnt (@{$incdirs}) { prt(" [$cnt]\n"); } } else { prt("FAILED to get INCLUDE dirs\n"); } pgm_exit(1,"TEST EXIT\n"); } ######################################### ### MAIN ### ### test(); parse_args(@ARGV); set_up(); process_in_file($in_file); 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); 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 = $arg; prt("Set input to [$in_file]\n") if (VERB1()); } shift @av; } if ($debug_on) { prtw("WARNING: Debug is ON\n"); if (length($in_file) == 0) { $in_file = $def_file; prt("Set DEFAULT input to [$in_file]\n"); ###$load_log = 2; } if (length($nsis_dir) == 0) { $nsis_dir = $def_nsis; prt("Set DEFAULT NSIS folder to [$nsis_dir]\n"); } if (length($out_file) == 0) { $out_file = $def_out; prt("Set DEFAULT out file to [$out_file]\n"); } if (!defined $macro_subs{'FGVersion'}) { $macro_subs{'FGVersion'} = $def_fgvers; prt("Set DEFAULT macro_subs{'FGVersion'} = ".$macro_subs{'FGVersion'}."\n"); } if (!defined $macro_subs{'OSGVersion'}) { $macro_subs{'OSGVersion'} = $def_osgver; prt("Set DEFAULT macro_subs{'OSGVersion'} = ".$macro_subs{'OSGVersion'}."\n"); } if (!defined $macro_subs{'OSGSoNumber'}) { $macro_subs{'OSGSoNumber'} = $def_osgnum; # 93 prt("Set DEFAULT macro_subs{'OSGSoNumber'} = ".$macro_subs{'OSGSoNumber'}."\n"); } } 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"); } } 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 (-o) = Write output to this file.\n"); } # eof - template.pl