5 my $programName = 'corrtohtml';
6 my $usage = "$programName [options] [inputFile [inputFile2 ...]]\n" .
7 "\t-b bookCode convert unspecified corrections to this book\n" .
9 "\t-i editorsInitials\n" .
11 "\t-s strips book information\n" .
12 "\t-v verbose reporting\n";
14 my $optsProcessed = 0;
16 my $editorInitials = "";
17 my $stripBookInfo = 0;
20 my $bookCodeReport = "";
22 while( $#ARGV > -1 && not $optsProcessed ) {
23 my $commandLineItem = shift @ARGV;
24 if( $commandLineItem eq "-b" ) {
25 $bookCode = shift @ARGV or die $usage;
26 &validateBookCode( $bookCode ) or die( "Error ($programName): unrecognized bookcode on command line \"$bookCode\"" );
28 elsif( $commandLineItem eq "-o" ) {
29 $outFile = shift @ARGV or die $usage;
31 elsif( $commandLineItem eq "-i" ) {
32 $editorInitials = shift @ARGV or die $usage;
34 elsif( $commandLineItem eq "-s" ) {
37 elsif( $commandLineItem eq "-v" ) {
40 elsif( $commandLineItem eq "--help" ) {
41 print $usage and exit;
44 unshift @ARGV, $commandLineItem;
51 my %sectionDocLookup = (
52 '_unknown' => '_unknown',
55 'dedicate' => 'dedicate',
56 'acknwldg' => 'acknwldg',
57 'credits' => 'acknwldg',
60 'gamerulz' => 'gamerulz',
61 'discplnz' => 'discplnz',
62 'camflage' => 'discplnz',
63 'hunting' => 'discplnz',
64 'sixthsns' => 'discplnz',
65 'tracking' => 'discplnz',
66 'healing' => 'discplnz',
67 'wepnskll' => 'discplnz',
68 'mndshld' => 'discplnz',
69 'mndblst' => 'discplnz',
70 'anmlknsp' => 'discplnz',
71 'mindomtr' => 'discplnz',
72 'mksumary' => 'discplnz',
73 'anmlctrl' => 'discplnz',
74 'curing' => 'discplnz',
75 'invsblty' => 'discplnz',
76 'psisurge' => 'discplnz',
77 'psiscrn' => 'discplnz',
78 'dvnation' => 'discplnz',
79 'wpnmstry' => 'discplnz',
80 'anmlmstr' => 'discplnz',
81 'deliver' => 'discplnz',
82 'assimila' => 'discplnz',
83 'hntmstry' => 'discplnz',
84 'pthmnshp' => 'discplnz',
85 'kaisurge' => 'discplnz',
86 'kaiscrn' => 'discplnz',
87 'nexus' => 'discplnz',
88 'gnosis' => 'discplnz',
90 'kalchemy' => 'discplnz',
92 'lessmcks' => 'powers',
93 'alchemy' => 'powers',
94 'sorcery' => 'powers',
95 'enchant' => 'powers',
96 'elementl' => 'powers',
97 'prophecy' => 'powers',
98 'psycmncy' => 'powers',
99 'evcation' => 'powers',
100 'highmcks' => 'powers',
101 'thamtrgy' => 'powers',
102 'telergy' => 'powers',
103 'physirgy' => 'powers',
104 'theurgy' => 'powers',
105 'visionry' => 'powers',
106 'necrmncy' => 'powers',
108 'moonston' => 'powers',
109 'equipmnt' => 'equipmnt',
110 'howcarry' => 'equipmnt',
111 'howmuch' => 'equipmnt',
112 'howuse' => 'equipmnt',
113 'cmbtrulz' => 'cmbtrulz',
114 'evasion' => 'cmbtrulz',
115 'lorecrcl' => 'lorecrcl',
116 'lcbonus' => 'lorecrcl',
117 'levels' => 'levels',
118 'primate' => 'levels',
119 'tutelary' => 'levels',
120 'mentora' => 'levels',
122 'archmstr' => 'levels',
123 'prncpln' => 'levels',
124 'imprvdsc' => 'imprvdsc',
125 'guardian' => 'imprvdsc',
126 'sunkght' => 'imprvdsc',
127 'sunlord' => 'imprvdsc',
128 'kaiwisdm' => 'kaiwisdm',
130 'numbered' => 'numbered',
153 'passing' => 'passing',
155 'action' => 'action',
156 'crsumary' => 'crsumary',
157 'smevazn' => 'crsumary',
158 'crtable' => 'crtable',
159 'random' => 'random',
160 'errata' => 'errata',
161 'errintro' => 'errata',
162 'errerr' => 'errata',
163 'footnotz' => 'footnotz',
164 'illstrat' => 'illstrat',
165 'primill' => 'illstrat',
166 'secill' => 'illstrat',
167 'license' => 'license',
168 'lic-pre' => 'license',
169 'lic-1' => 'license',
170 'lic-1-0' => 'license',
171 'lic-1-1' => 'license',
172 'lic-1-2' => 'license',
173 'lic-1-3' => 'license',
174 'lic-1-4' => 'license',
175 'lic-1-5' => 'license',
176 'lic-1-6' => 'license',
177 'lic-1-7' => 'license',
178 'lic-2' => 'license',
179 'lic-2-0' => 'license',
180 'lic-2-1' => 'license',
181 'lic-2-2' => 'license',
182 'lic-2-3' => 'license',
183 'lic-2-4' => 'license',
184 'lic-2-5' => 'license',
185 'lic-3' => 'license',
186 'lic-3-0' => 'license',
187 'lic-3-1' => 'license',
188 'lic-4' => 'license',
189 'lic-4-0' => 'license',
190 'lic-5' => 'license',
191 'lic-5-0' => 'license',
192 'lic-6' => 'license',
193 'lic-6-0' => 'license',
194 'lic-6-1' => 'license'
197 my %sectionTitleLookup = (
198 '_unknown' => '_unknown',
199 'toc' => 'Table of Contents',
200 'title' => 'Title Page',
201 'dedicate' => 'Dedication',
202 'acknwldg' => 'Acknowledgements',
203 'coming' => 'Of the Coming of Grey Star',
204 'tssf' => 'The Story So Far . . .',
205 'gamerulz' => 'The Game Rules',
206 'discplnz' => '. . . Disciplines',
207 'powers' => 'Magical Powers',
208 'equipmnt' => 'Equipment',
209 'cmbtrulz' => 'Rules for Combat',
210 'lorecrcl' => 'Lore-circles of the Magnakai',
211 'levels' => 'Levels of . . . Mastery',
212 'imprvdsc' => 'Improved . . . Disciplines',
213 'kaiwisdm' => '. . . Wisdom',
214 'sage' => 'Sage Advice',
215 'numbered' => 'Numbered Sections',
217 'part2' => 'Part II',
218 'ill1' => 'Illustration 1',
219 'ill2' => 'Illustration 2',
220 'ill3' => 'Illustration 3',
221 'ill4' => 'Illustration 4',
222 'ill5' => 'Illustration 5',
223 'ill6' => 'Illustration 6',
224 'ill7' => 'Illustration 7',
225 'ill8' => 'Illustration 8',
226 'ill9' => 'Illustration 9',
227 'ill10' => 'Illustration 10',
228 'ill11' => 'Illustration 11',
229 'ill12' => 'Illustration 12',
230 'ill13' => 'Illustration 13',
231 'ill14' => 'Illustration 14',
232 'ill15' => 'Illustration 15',
233 'ill16' => 'Illustration 16',
234 'ill17' => 'Illustration 17',
235 'ill18' => 'Illustration 18',
236 'ill19' => 'Illustration 19',
237 'ill20' => 'Illustration 20',
238 'passing' => 'Passing of the Shianti',
240 'action' => 'Action Chart',
241 'crsumary' => 'Combat Rules Summary',
242 'crtable' => 'Combat Results Table',
243 'random' => 'Random Number Table',
244 'errata' => 'Errata',
245 'footnotz' => 'Footnotes',
246 'illstrat' => 'Table of Illustrations',
247 'license' => 'Project Aon License'
250 if( $bookCode ne "" ) {
251 $bookCodeReport = " [$bookCode]";
253 ################################################################################
254 # Normalize Lines and Whitespace
256 foreach my $line (@lines) {
260 $document =~ s/[[:space:]]{2,}/ /g; # collapse spaces
261 $document =~ s/(\(er?\)|\(ne?\)|\(ft?\)|\(ce\)|\(cn\)|\(cf\)|\(re\)|\(rn\)|\(rf\)|\(\?\??\))/\n$1/g; # break lines
262 $document =~ s/^[[:space:]]*\n//g; # remove blank lines
263 @lines = split( m/ *\n/, $document );
265 ################################################################################
268 my $commentRegex = qr{\[[[:space:]]*(([^[:space:]:]*)[[:space:]]*:)?[[:space:]]*([^]]*)\]};
269 my $sectionNumberRegex = qr{^\(([^)][^)])*\) # type: $1
271 ([[:digit:]]*[[:alpha:]]+[[:space:]]+)? # book: $2
272 ([[:digit:]]+) # section: $3
274 \#([[:digit:]]+))? # issue: $4
276 (.*?) # correction: $5
278 my $sectionIDRegex = qr{^\(([^)][^)])*\) # type: $1
280 ([[:digit:]]*[[:alpha:]]+[[:space:]]+)? # book: $2
281 ([^:[:space:]]*) # section: $3
283 \#([[:digit:]]+))? # issue: $4
285 (.*?) # correction: $5
288 foreach my $line (@lines) {
289 $line =~ s{&} {&}g; # escape for HTML
290 $line =~ s{<} {<}g; # "
291 $line =~ s{>} {>}g; # "
293 while( $line =~ m{$commentRegex} ) {
294 if( (not defined( $2 )) || $2 eq "" ) {
295 $line =~ s{$commentRegex}{<div class="cm $editorInitials">$3</div>};
297 my $initials = lc( $2 );
298 $line =~ s{$commentRegex}{<div class="cm $initials">$3</div>};
300 if( $3 =~ m/^[[:space:]]*$/ ) {
301 warn( "Warning ($programName)$bookCodeReport: empty comment found\n" );
305 if( $line =~ m{$sectionNumberRegex} ) {
309 &validateBookCode( $book ) or die( "Error ($programName)$bookCodeReport: unrecognized bookcode in input corrections \"$book\"" );
313 warn( "Warning ($programName)$bookCodeReport: entry with unspecified book coerced to $bookCode: $line\n" );
317 if( defined $4 ) { $issue = $4; }
318 my $caseFoldSection = lc( $3 );
319 if( $book ne "" && not $stripBookInfo ) {
320 $line =~ s{$sectionNumberRegex}{<div class="$1"><!-- $book--><a href="sect$caseFoldSection.htm">$caseFoldSection</a> #$issue:$5</div>\n};
323 $line =~ s{$sectionNumberRegex}{<div class="$1"><a href="sect$caseFoldSection.htm">$caseFoldSection</a> #$issue:$5</div>\n};
326 elsif( $line =~ m{$sectionIDRegex} ) {
327 my $caseFoldSection = lc( $3 );
328 exists $sectionDocLookup{$caseFoldSection} && defined $sectionDocLookup{$caseFoldSection}
329 or die( "Error ($programName)$bookCodeReport: don\'t understand section ID \"$caseFoldSection\" in $line" );
330 exists $sectionTitleLookup{$sectionDocLookup{$caseFoldSection}} && defined $sectionTitleLookup{$sectionDocLookup{$caseFoldSection}}
331 or die( "Error ($programName)$bookCodeReport: section ID \"$caseFoldSection\" doesn\'t have an associated title" );
337 &validateBookCode( $book ) or die( "Error ($programName)$bookCodeReport: unrecognized bookcode in input corrections \"$book\"" );
341 warn( "Warning ($programName)$bookCodeReport: entry with unspecified book coerced to $bookCode: $line\n" );
345 if( defined $4 ) { $issue = $4; }
347 if( $book ne "" && not $stripBookInfo ) {
348 $line =~ s{$sectionIDRegex}{<div class="$1"><!-- $book--><a href="$sectionDocLookup{$caseFoldSection}.htm">$sectionTitleLookup{$sectionDocLookup{$caseFoldSection}}</a> \#$issue:$5</div>\n};
351 $line =~ s{$sectionIDRegex}{<div class="$1"><a href="$sectionDocLookup{$caseFoldSection}.htm">$sectionTitleLookup{$sectionDocLookup{$caseFoldSection}}</a> \#$issue:$5</div>\n};
355 die( "Error ($programName)$bookCodeReport: unable to parse line: $line\n" );
358 $line =~ s{class="\?\??"} {class="u"};
359 $line =~ s{class="er"} {class="e"};
360 $line =~ s{class="ne"} {class="n"};
361 $line =~ s{class="ft"} {class="f"};
363 if( $line =~ m/(\(.{,4}\))|(\[.{,4}\])/ ) {
364 warn( "Warning ($programName)$bookCodeReport: possible malformed correction entry: $line\n" );
368 ################################################################################
371 if( $outFile ne "" ) {
372 open( OUTFILE, ">$outFile" ) or die( "Error ($programName)$bookCodeReport: Unable to open output file \"$outFile\" for writing: $!" );
373 print OUTFILE @lines;
380 ################################################################################
383 sub validateBookCode {
386 # bookCode typically has some space after real data
387 $bookCode =~ s{[[:space:]]+}{}g;
430 return exists $books{ $bookCode };