#
# Updates the NS manual using Balance.txt
#
local ($kVersion, $kFileSpecifier, $kBalanceFileName, $kTempFileName,%BalanceVars,@BalanceUpdateTime);
#
# Changelog
#
# v1.1 - Karl Patrick
#
# tag parser / content replacer
# - changed tag structure to be SGML compliant and use an ns namespace for ease of validation, e.g. value
# - widened definition of content between nsvalue tags to include all characters except '<' so non-word characters can become placeholders
# - added global processing switch for the tag substitution operators (they now replace multiple matches in a line)
# - changed nsinverse tag to print inverse value with 2 decimal places
# - changed nspercent tag to print percentile after the numeric value and never use a decimal place
# - added fourth tag type, nsdate, which inserts the timestamp of the Balance.txt file in whatever format the tag specifies
# - TODO: use m// operator to match ns namespace tags and formally parse tag attributes
# - TODO: parse entire file at once to lose dependancy on line breaks
# file handling
# - added optional command line statements to manually specify the balance file name [arg0] and files to parse [all other args]
# - default behavior remains unchanged if no args are supplied
# - the current directory is scanned for files to update if only one argument is given
# - moved filtering of file names to default array construction; any explicitly named file will now be processed
# - replaced native system calls for file handling with perl function calls
# - added early termination of program on balance.txt file read failure
# - added automatic deletion of temp file if no replacements were made to the original
# - TODO: drop use of temp file in favor of local string storage, use rename-to-.bak and update paradigm for files
# misc
# - removed previously commented out debug print statements
# - replaced some of the globals with subroutine arguments / locals
# - changed output format to be easier to scan for large numbers of files
#
# v1.0 Original Version - Charlie Cleveland
#
#
# Constants
#
$kVersion = "v1.2";
$kFileSpecifier = ".php";
$kBalanceFileName = "c:\\Web\\ns\\Balance.txt";
$kTempFileName = "UpdateManual.temp";
local $blankLine = "....................................................................";
sub Main;
Main();
# Subroutine that checks file out of Perforce, does a search and replace on all values, then reverts the file if unchanged
sub ProcessFileName
{
# Read subroutine args
my $theFileName = shift(@_);
use POSIX qw(strftime);
# Read in whole file
my $printString = sprintf("READING \"$theFileName\"");
if(!open(FILE2, $theFileName))
{
printf("%s%s[FAILURE]\n",$printString,substr($blankLine,length($printString)));
return 0;
}
printf("%s%s[SUCCESS]\n",$printString,substr($blankLine,length($printString)));
# Open tempoarary file for writing
if(!open(FILE3, '>', $kTempFileName))
{
$printString = sprintf("WRITING \"$theFileName\"");
printf("%s%s[FAILURE]\n",$printString,substr($blankLine,length($printString)));
return 0;
}
# Check for a match
my $theNumReplacements = 0;
while()
{
local $theCurrentLine = $_;
if($theCurrentLine =~ s/()[^<]*(<\/ns:value>)/$1 . $BalanceVars{$2} . $3/ge)
{ $theNumReplacements++; }
# This can't be in an else clause any more because both types may appear on the same line
if($theCurrentLine =~ s/()[^<]*(<\/ns:percent>)/$1 . sprintf("%.0f%%",$BalanceVars{$2}*100) . $3/ge)
{ $theNumReplacements++; }
if($theCurrentLine =~ s/()[^<]*(<\/ns:inverse>)/$1 . sprintf("%.2f",1\/$BalanceVars{$2}) . $3/ge)
{ $theNumReplacements++; }
if($theCurrentLine =~ s/()[^<]*(<\/ns:date>)/$1 . strftime($2,@BalanceUpdateTime) . $3/ge)
{ $theNumReplacements++; }
print FILE3 $theCurrentLine;
}
close FILE2;
close FILE3;
if($theNumReplacements > 0) # Update if a match was present
{
$printString = sprintf("UPDATING \"$theFileName\"");
if(unlink($theFileName) && rename($kTempFileName,$theFileName))
{
printf("%s%s[SUCCESS]\n",$printString,substr($blankLine,length($printString)));
return 1;
}
else
{
printf("%s%s[FAILURE]\n",$printString,substr($blankLine,length($printString)));
return 0;
}
}
else
{
unlink($kTempFileName);
return 1;
}
}
sub ReadBalanceVariables
{
# Read Balance file
my $printString = sprintf("PARSING \"$kBalanceFileName\"");
open(FILE, $kBalanceFileName);
@BalanceUpdateTime = localtime((stat(FILE))[9]);
my $theSuccess = 0;
# Print contents of Balance.txt
while()
{
my $theCurrentBalanceLine = $_;
if($theCurrentBalanceLine =~ /#define/)
{
my @theCurrentTokens;
@theCurrentTokens = split();
if($#theCurrentTokens == 2)
{
my $tokenOne = $theCurrentTokens[1];
my $tokenTwo = $theCurrentTokens[2];
$BalanceVars{$tokenOne} = $tokenTwo;
$theSuccess = 1;
}
}
}
close(FILE);
printf("%s%s[%s]\n",$printString,substr($blankLine,length($printString)),$theSuccess ? "SUCCESS" : "FAILURE");
return $theSuccess;
}
sub Main
{
print "\nRunning Natural Selection Manual Updater $kVersion\n\n";
if($#ARGV >= 0) # First arg is the Balance document name
{
$kBalanceFileName = $ARGV[0];
shift(@ARGV); # Drop first argument
}
# Read in the contents of Balance.txt to use for replacement
if(ReadBalanceVariables() == 0)
{ return; } # Return on failure
if($#ARGV >= 0) # Remaining args are files to parse
{ @theHTMLFiles = @ARGV }
else
{
# Search through all the files in the working directory
opendir(DIR, ".");
local @AllFiles = readdir(DIR);
@theHTMLFiles = grep(/$kFileSpecifier/i,@AllFiles);
closedir(DIR);
}
# Process each file
foreach (@theHTMLFiles)
{ ProcessFileName($_); }
}