#!/usr/bin/perl
#
# This program marks up the V3.5 SRD with handy cross-reference links.
# It is pretty fragile.
#
# TO-DO LIST:
# Export characters in simple HTML
# Create index pages.
# Create A-Z lists at the top of certain pages
# Create a scheme such that if a heading is defined in more than one place,
# created links are directed to the closer one (or the user intervenes).
# Prevent modification of lines between and
#
use strict;
use IO::Handle;
sub TitleCase
{
my $parm = shift;
my @words = split(' ', $parm);
my $result = join(' ', map { ucfirst lc } @words);
return $result;
}
# This causes status messages to be displayed immediately,
# but comes at the price of decreased output performance on
# STDOUT (boo-hoo).
autoflush STDOUT 1;
# The place to find the original files
my $html_dir = "/cygdrive/c/palmSRD/orig";
# The place to put the processed files
my $out_dir = "/cygdrive/c/palmSRD/html";
rmdir $out_dir || "Can't delete directory '$out_dir'\n";
mkdir $out_dir || die "Can't create output directory '$out_dir'\n";
chdir $out_dir || die "Can't change to directory '$html_dir'\n";
my @orig_files = glob "$html_dir/*.html";
# Make a copy of the original files so that we don't damange them.
`cp @orig_files $out_dir`;
# The list of all files
my @all_files = glob "*.html";
# Global variable used to hold the mappings from a target
# word or phrase to the anchor tag where that word or phrase
# is defined.
my %target_to_link;
#
# Global variable containing list of all indices produced.
#
my @indices;
#
# Get rid of all of the font tags with size=5 or size=3.
#
sub NukeFontTags
{
print "Removing FONT tags:";
# The list of files containing target definitions
my @target_files = glob "*.html";
# The file currently being processed.
my $filename;
my $outfilename = "temp";
for $filename (@target_files) {
my $IN;
my $OUT;
$filename =~ m/(.)/;
print uc $1;
open IN, $filename || die "Can't open file '$filename'\n";
open OUT, ">$outfilename" || die "Can't open output file '$outfilename'\n";
my $line;
while ($line = ) {
my @tagList = ();
push @tagList, "dummy";
# Nuke all font tags
while ($line =~ s/(\.*?\<\/font\>)/QQQ$#tagList/i) {
push @tagList, $1;
}
$line =~ s/\//gi;
$line =~ s/\<\/font\>//gi;
while ($line =~ s/([^\<]+)/RRR$#tagList/i) {
push @tagList, $1;
}
while ($line =~ s/<\/?font.*?>//ig) {
}
if ($line =~ /\<.?font.*?\>/i) {
print "Still a font tag in $filename: '$line'\n";
}
while ($line =~ s/QQQ([0-9]+)/@tagList[$1+1]/) {
}
if ($line =~ /QQQ/) {
print "QQQ Still in $filename: '$line'\n";
}
# $line =~ s/QQQ/$fonttag/;
while ($line =~ s/RRR([0-9]+)/@tagList[$1+1]\<\/font\>/) {
}
if ($line =~ /RRR/) {
print "RRR Still in $filename: '$line'\n";
}
# $line =~ s/RRR/$fonttag2\<\/font\>/;
print OUT $line;
}
close IN;
close OUT;
# Replace input with output
rename $outfilename, $filename || die "Can't rename '$outfilename' to '$filename'\n";
}
print "\n";
}
#
# Find all the items worth indexing. These are identified
# by having a
tag BY ITS SELF on the preceding line,
# and this line being terminated by a
#
sub TagDestinations
{
my $prefix = shift;
print "Creating anchors for $prefix.";
# The list of files containing target definitions
my @target_files = glob "$prefix*.html";
# The file currently being processed.
my $filename;
my $outfilename = "temp";
my %mapping;
for $filename (@target_files) {
my $IN;
my $OUT;
print ".";
open IN, $filename || die "Can't open file '$filename'\n";
open OUT, ">$outfilename" || die "Can't open output file '$outfilename'\n";
my $line;
while ($line = ) {
if ($line =~ /^\
\r?$/) {
$line = || die "Can't read.\n";
# if ($line =~ /([^\<\>\(\)\[\]]{2,})\s*.*\
/) {
if ($line =~ /((armor proficiency \(\w+\))|^([^\<\>\(\)\[\]]{2,}))(\s*.*)\
(.*)/i) {
#
# $1 contains the name of a target. Save it for later and also
# mark it up as a header and a destination tag.
#
my $rest_of_name = $4;
my $target_name = &TitleCase($1);
my $everythingElse = $5;
if (length $target_name > 50) {
print OUT $line;
}
else {
# Use all lower-case for keys for consistency
my $lc_target_name = lc $target_name;
my $tag_name = "__$lc_target_name,,";
$tag_name =~ s/[ ,\"\'\(\)]/_/g;
# print " $target_name\t";
# Create the mapping from key to link
$mapping{$lc_target_name}
= "$target_name";
# print "$mapping{$lc_target_name}\n";
print OUT "\n\n$everythingElse";
# print OUT "\n
*$target_name$2
\n$3";
# If this target has a comma in it, then create the
# mapping for the non-comma'd version.
# e.g. Stoneskin, Greater => Greater Stoneskin
# Create the mapping from key to link
if ($lc_target_name =~ /([^,]+)\,\s*(.+)/) {
my $alt_target_name = "$2 $1";
$mapping{$alt_target_name}
= "$target_name";
# print " $alt_target_name\t";
# print "$mapping{$alt_target_name}\n";
}
}
}
}
else {
print OUT $line;
}
}
close IN;
close OUT;
# Replace input with output
rename $outfilename, $filename || die "Can't rename '$outfilename' to '$filename'\n";
}
print "\n";
#
# Create an index file for these topics.
#
&CreateIndexPage($prefix, \%mapping);
#
# Merge the mapping for this fileset into the master map.
#
for my $key (keys %mapping) {
$target_to_link{$key} = $mapping{$key};
}
}
sub MarkupLinks
{
my $fileList = shift || "*.html";
my $target_matcher = join('|', reverse sort { length($a) <=> length($b) } keys(%target_to_link));
$target_matcher =~ s/\(/\\\(/g;
$target_matcher =~ s/\)/\\\)/g;
$target_matcher = "($target_matcher)";
print "Marking up links";
# The list of files containing target definitions
my @target_files = glob $fileList;
foreach (@target_files) {
m/^(.)/;
print "$1";
}
print "\n";
print "Progress so far:";
# print $target_matcher;
# exit;
# The file currently being processed.
my $filename;
my $outfilename = "temp";
for $filename (@target_files) {
my $IN;
my $OUT;
open IN, $filename || die "Can't open file '$filename'\n";
open OUT, ">$outfilename" || die "Can't open output file '$outfilename'\n";
$filename =~ m/(.)/;
print uc $1;
my $line;
while ($line = ) {
# $line =~ s/($target_matcher)/$target_to_link{lc $1}/gi;
# $line =~ s/(\<[bi]\>|[1-9]\s+)($target_matcher)/$1$target_to_link{lc $2}/gi;
# $line =~ s/\<([bi])\>($target_matcher)/<$1>$target_to_link{lc $2}/gi;
$line =~ s/(\W+|^|^)($target_matcher)(?=[^\":\w]+)/$1$target_to_link{lc $2}/ogi;
print OUT $line;
}
close IN;
close OUT;
# Replace input with output
rename $outfilename, $filename || die "Can't rename '$outfilename' to '$filename'\n";
}
print "\n";
}
sub CreateIndexPage
{
my $prefix = shift;
my $indexName = $prefix . "Index.html";
my $hashRef = shift;
my %mapping = %$hashRef;
if (scalar (keys %mapping)) {
print "Creating $indexName\n";
}
else {
print "$prefix is an empty index.\n";
return;
}
my $OUT;
open OUT, ">$indexName";
print OUT "\n";
print OUT "V3.5 SRD Index\n";
print OUT "\n";
print OUT "$prefix Index
\n";
my $topic;
#
# Generate the alphabet links to the subsections of this index.
my $firstLetter = "?";
for $topic (sort keys %mapping) {
# Create a new anchor if necessary
if (substr($topic, 0, 1) ne $firstLetter) {
$firstLetter = substr($topic, 0, 1);
print OUT "\[" . uc $firstLetter . "\]\n";
}
}
#
# If this is the master index, then write out topical index links.
#
if ($prefix eq "Master") {
print OUT "
\n";
for $topic (sort @indices) {
print OUT "$topic\n";
}
# Also include the characters here
print OUT "Landorel\n";
print OUT "Ptom\n";
print OUT "
\n";
}
push @indices, $prefix;
#
# Now write out the actual sections of this index.
#
for $topic (sort keys %mapping) {
# Create a new anchor if necessary
if (substr($topic, 0, 1) ne $firstLetter) {
$firstLetter = substr($topic, 0, 1);
print OUT "\n";
}
print OUT "$topic ";
}
print OUT "\n";
print OUT "\n";
close OUT;
}
&NukeFontTags();
# Tag the destinations in increasing order of their importance.
# This is necessary because later headings over-write earlier ones.
&TagDestinations("AbilitiesAndConditions");
&TagDestinations("CarryingAndExploration");
&TagDestinations("Monsters");
&TagDestinations("MonsterFeats");
&TagDestinations("TypesSubtypesAbilities");
&TagDestinations("Combat");
&TagDestinations("Spell");
#&TagDestinations("MagicItems");
&TagDestinations("Feats");
&TagDestinations("Skills");
&TagDestinations("Classes");
&TagDestinations("PrestigeClasses");
&TagDestinations("Basics");
&TagDestinations("Description");
&TagDestinations("Races");
#&TagDestinations("psionicd");
# Now create the master index.
&CreateIndexPage("Master", \%target_to_link);
&MarkupLinks("*.html");
print "Done!\n";