|
1 #!perl |
|
2 # fsh-builddocs |
|
3 # |
|
4 # Copyright (c) 2010 Accenture. All rights reserved. |
|
5 # This component and the accompanying materials are made available |
|
6 # under the terms of the "Eclipse Public License v1.0" |
|
7 # which accompanies this distribution, and is available |
|
8 # at the URL "http://www.eclipse.org/legal/epl-v10.html". |
|
9 # |
|
10 # Initial Contributors: |
|
11 # Accenture - Initial contribution |
|
12 # |
|
13 # Description: |
|
14 # fsh-builddocs - A tool that generates HTML documentation from POD source files. |
|
15 |
|
16 use strict; |
|
17 use Cwd; |
|
18 use Pod::Html; |
|
19 use IO::File; |
|
20 use File::Basename; |
|
21 use File::Path; |
|
22 use File::Copy; |
|
23 use Getopt::Long; |
|
24 use FindBin; |
|
25 use lib "$FindBin::Bin"; |
|
26 use fshu; |
|
27 use CommandInfoFile; |
|
28 |
|
29 |
|
30 # |
|
31 # Constants. |
|
32 # |
|
33 |
|
34 my $kCpp = "\\epoc32\\gcc\\bin\\cpp -I. "; |
|
35 |
|
36 |
|
37 # |
|
38 # Globals. |
|
39 # |
|
40 |
|
41 my %options = ( |
|
42 verbose => 0, |
|
43 includes => [] |
|
44 ); |
|
45 |
|
46 |
|
47 # |
|
48 # Main. |
|
49 # |
|
50 |
|
51 my $podListFile = ProcessCommandLine(); |
|
52 my $podListDirName = dirname($podListFile); |
|
53 my $cwd = cwd(); |
|
54 chdir ($podListDirName) or die "Error: Couldn't chdir to '$podListDirName' - $!\n"; |
|
55 my $spec; |
|
56 |
|
57 eval { |
|
58 $spec = ParsePodList($podListFile); |
|
59 CopyCss($spec); |
|
60 CopyPod($spec); |
|
61 IdentifyIndexPod($spec); |
|
62 IdentifyCifPod($spec); |
|
63 GenerateIndexPod($spec); |
|
64 GenerateCifPod($spec); |
|
65 BuildHtml($spec); |
|
66 }; |
|
67 my $error = $@; |
|
68 |
|
69 chdir ($cwd) or die "Error: Couldn't chdir back to '$cwd': $!\n"; |
|
70 die $error if ($error); |
|
71 |
|
72 |
|
73 # |
|
74 # Subs. |
|
75 # |
|
76 |
|
77 sub ProcessCommandLine { |
|
78 my $help; |
|
79 GetOptions('h|help' => \$help, |
|
80 'v|verbose' => \$options{verbose}, |
|
81 'w|what' => \$options{what}, |
|
82 'c|clean' => \$options{clean}, |
|
83 'i|include=s' => $options{includes}) or DisplayHelp(); |
|
84 DisplayHelp() if ($help); |
|
85 warn "Invalid arguments\n" and DisplayHelp() unless (@ARGV == 1); |
|
86 return shift @ARGV; |
|
87 } |
|
88 |
|
89 sub DisplayHelp { |
|
90 require Pod::Text; |
|
91 print "\n"; |
|
92 my $parser = Pod::Text->new(); |
|
93 $parser->parse_from_file($0); |
|
94 exit; |
|
95 } |
|
96 |
|
97 sub ParsePodList { |
|
98 my $podListFileName = shift; |
|
99 |
|
100 local $_; |
|
101 my $command = $kCpp . join (' ', map {"-I$_"} @{$options{includes}}) . " $podListFileName 2>&1 |"; |
|
102 print "Running '$command'\n" if ($options{verbose}); |
|
103 open (CPP, $command) or die "Error: Couldn't run 'cpp.exe': $!\n"; |
|
104 my $spec; |
|
105 |
|
106 my $currentDir; |
|
107 my $currentFile; |
|
108 my $currentLine = 0; |
|
109 while (my $line = <CPP>) { |
|
110 ++$currentLine; |
|
111 $line =~ s/^\s+//; |
|
112 next if (!$line); # Blank lines. |
|
113 |
|
114 if ($line =~ /^#\s+(\d+)\s+"([^"]+)"/) { |
|
115 $currentLine = $1; |
|
116 $currentFile = fshu::TidyPath($2); |
|
117 $currentDir = dirname($currentFile); |
|
118 } |
|
119 elsif ($line =~ /^doc-root\s+(\S+)\s*$/) { |
|
120 $spec->{docRoot} = fshu::TidyPath($1); |
|
121 } |
|
122 elsif ($line =~ /^temp-root\s+(\S+)\s*$/) { |
|
123 $spec->{tempRoot} = fshu::TidyPath($1); |
|
124 } |
|
125 elsif ($line =~ /^css\s+(\S+)\s*$/) { |
|
126 $spec->{cssFile} = fshu::TidyPath("$currentDir\\" . fshu::TidyPath($1)); |
|
127 } |
|
128 elsif ($line =~ /^pod\s+(\S+)\s+(\S+)\s*$/) { |
|
129 my $podFileName = fshu::TidyPath("$currentDir\\" . fshu::TidyPath($1)); |
|
130 my $htmlFileName = fshu::TidyPath($2); |
|
131 |
|
132 # If this HTML file matches one we already have in the list, allow this one to override. |
|
133 my $found = 0; |
|
134 foreach my $podFile (@{$spec->{podFiles}}) { |
|
135 if (lc($podFile->{htmlFileName}) eq lc($htmlFileName)) { |
|
136 $podFile->{podFileName} = $podFileName; |
|
137 $found = 1; |
|
138 last; |
|
139 } |
|
140 } |
|
141 unless ($found) { |
|
142 push (@{$spec->{podFiles}}, { |
|
143 podFileName => $podFileName, |
|
144 htmlFileName => $htmlFileName |
|
145 }); |
|
146 } |
|
147 } |
|
148 elsif ($line =~ /^index\s+(\S+)/) { |
|
149 my $htmlDirName = fshu::TidyPath($1); |
|
150 my $podFileName; |
|
151 if ($line =~ /^index\s+\S+\s+(\S+)\s*$/) { |
|
152 $podFileName = fshu::TidyPath("$currentDir\\" . fshu::TidyPath($1)); |
|
153 } |
|
154 push (@{$spec->{indices}}, { |
|
155 podFileName => $podFileName, |
|
156 htmlDirName => $htmlDirName |
|
157 }); |
|
158 } |
|
159 elsif ($line =~ /^cif\s+(\S+)\s+(\S+)/) { |
|
160 my $cifDirName = fshu::TidyPath($1); |
|
161 my $htmlDirName = fshu::TidyPath($2); |
|
162 my $podFileName; |
|
163 if ($line =~ /^cif\s+\S+\s+\S+\s+(\S+)\s*$/) { |
|
164 $podFileName = fshu::TidyPath("$currentDir\\" . fshu::TidyPath($1)); |
|
165 } |
|
166 push (@{$spec->{cifIndices}}, { |
|
167 podFileName => $podFileName, |
|
168 htmlDirName => $htmlDirName, |
|
169 cifDirName => $cifDirName |
|
170 }); |
|
171 } |
|
172 else { |
|
173 die "Error: Invalid pod-list line at $currentFile($currentLine):\n$line"; |
|
174 } |
|
175 } |
|
176 |
|
177 close (CPP); |
|
178 |
|
179 die "Error: No 'doc-root' in pod-list\n" unless ($spec->{docRoot}); |
|
180 die "Error: No 'temp-root' in pod-list\n" unless ($spec->{tempRoot}); |
|
181 return $spec; |
|
182 } |
|
183 |
|
184 sub CopyCss { |
|
185 my $spec = shift; |
|
186 |
|
187 if ($spec->{cssFile}) { |
|
188 my $target = "$spec->{docRoot}\\" . basename($spec->{cssFile}); |
|
189 if ($options{what}) { |
|
190 print "$target\n"; |
|
191 } |
|
192 elsif ($options{clean}) { |
|
193 unlink ($target); |
|
194 } |
|
195 else { |
|
196 fshu::CopyFile($spec->{cssFile}, $target, $options{verbose}); |
|
197 } |
|
198 } |
|
199 } |
|
200 |
|
201 sub CopyPod { |
|
202 my $spec = shift; |
|
203 |
|
204 foreach my $podEntry (@{$spec->{podFiles}}) { |
|
205 my $targetFileName = "$spec->{tempRoot}\\$podEntry->{htmlFileName}"; |
|
206 $targetFileName =~ s/\.[^\.]+$/\.pod/; |
|
207 $podEntry->{tempPodFileName} = $targetFileName; |
|
208 if ($options{what}) { |
|
209 # Do nothing. |
|
210 } |
|
211 elsif ($options{clean}) { |
|
212 unlink ($targetFileName); |
|
213 } |
|
214 else { |
|
215 fshu::CopyFile($podEntry->{podFileName}, $targetFileName, $options{verbose}); |
|
216 } |
|
217 } |
|
218 } |
|
219 |
|
220 sub IdentifyIndexPod { |
|
221 my $spec = shift; |
|
222 |
|
223 # This sub-routine identifies the index POD files that will be generated later on. |
|
224 # This is done as a separate phase to allow indices to contain links generated POD. |
|
225 |
|
226 foreach my $indexEntry (@{$spec->{indices}}) { |
|
227 push (@{$spec->{podFiles}}, { |
|
228 podFileName => "$indexEntry->{htmlDirName}.pod", |
|
229 tempPodFileName => "$spec->{tempRoot}\\$indexEntry->{htmlDirName}.pod", |
|
230 htmlFileName => "$indexEntry->{htmlDirName}.html" |
|
231 }); |
|
232 } |
|
233 } |
|
234 |
|
235 sub GenerateIndexPod { |
|
236 my $spec = shift; |
|
237 |
|
238 foreach my $indexEntry (@{$spec->{indices}}) { |
|
239 my $tempDir = "$spec->{tempRoot}\\$indexEntry->{htmlDirName}"; |
|
240 my $indexPodFileName = "$tempDir.pod"; |
|
241 |
|
242 if ($options{what}) { |
|
243 # Do nothing. |
|
244 } |
|
245 elsif ($options{clean}) { |
|
246 unlink ($indexPodFileName); |
|
247 } |
|
248 else { |
|
249 print "Building $indexPodFileName\n" if ($options{verbose}); |
|
250 fshu::MakePath($tempDir); |
|
251 open (INDEX, ">$indexPodFileName") or die "Error: Couldn't open '$indexPodFileName' for writing - $!\n"; |
|
252 |
|
253 # Copy the contents of the introductory POD. |
|
254 if ($indexEntry->{podFileName}) { |
|
255 open (POD, $indexEntry->{podFileName}) or die "Error: Couldn't open '$indexEntry->{podFileName}' for reading - $!\n"; |
|
256 while (my $line = <POD>) { |
|
257 print INDEX $line; |
|
258 } |
|
259 close (POD); |
|
260 } |
|
261 else { |
|
262 print INDEX "=head1 $indexEntry->{htmlDirName}\n\n"; |
|
263 } |
|
264 |
|
265 # Add the links. |
|
266 my $htmlDir = lc($indexEntry->{htmlDirName}); |
|
267 foreach my $podEntry (@{$spec->{podFiles}}) { |
|
268 if (lc(dirname($podEntry->{htmlFileName})) eq $htmlDir) { |
|
269 my $fileName = $podEntry->{htmlFileName}; |
|
270 $fileName =~ s/\.[^\.]+$//; |
|
271 $fileName =~ s/\\/\//g; |
|
272 my $presentableFileName = basename($fileName); |
|
273 $presentableFileName = ucfirst($presentableFileName); |
|
274 $presentableFileName =~ s/_/ /g; |
|
275 $fileName =~ s/\//::/g; |
|
276 print INDEX "\nL<$presentableFileName|$fileName>\n"; |
|
277 } |
|
278 } |
|
279 |
|
280 close (INDEX); |
|
281 } |
|
282 } |
|
283 } |
|
284 |
|
285 sub IdentifyCifPod { |
|
286 my $spec = shift; |
|
287 |
|
288 # This sub-routine identifies the CIF index POD files that will be generated later on. |
|
289 # This is done as a separate phase to allow indices to contain links generated POD. |
|
290 |
|
291 foreach my $podEntry (@{$spec->{cifIndices}}) { |
|
292 push (@{$spec->{podFiles}}, { |
|
293 podFileName => "$podEntry->{htmlDirName}.pod", |
|
294 tempPodFileName => "$spec->{tempRoot}\\$podEntry->{htmlDirName}.pod", |
|
295 htmlFileName => "$podEntry->{htmlDirName}.html" |
|
296 }); |
|
297 } |
|
298 } |
|
299 |
|
300 sub GenerateCifPod { |
|
301 my $spec = shift; |
|
302 |
|
303 foreach my $podEntry (@{$spec->{cifIndices}}) { |
|
304 my $tempDir = "$spec->{tempRoot}\\$podEntry->{htmlDirName}"; |
|
305 my $indexPodFileName = "$tempDir.pod"; |
|
306 my $indexFile; |
|
307 |
|
308 if ($options{what}) { |
|
309 # Do nothing. |
|
310 } |
|
311 elsif ($options{clean}) { |
|
312 unlink ($indexPodFileName); |
|
313 } |
|
314 else { |
|
315 print "Building $indexPodFileName\n" if ($options{verbose}); |
|
316 fshu::MakePath($tempDir); |
|
317 $indexFile = IO::File->new(">$indexPodFileName") or die "Error: Couldn't open '$indexPodFileName' for writing: $!\n"; |
|
318 |
|
319 # Copy the contents of the introductory POD. |
|
320 if ($podEntry->{podFileName}) { |
|
321 open (POD, $podEntry->{podFileName}) or die "Error: Couldn't open '$podEntry->{podFileName}' for reading - $!\n"; |
|
322 while (my $line = <POD>) { |
|
323 print $indexFile $line; |
|
324 } |
|
325 close (POD); |
|
326 } |
|
327 else { |
|
328 print $indexFile "=head1 $podEntry->{htmlDirName}\n\n"; |
|
329 } |
|
330 |
|
331 # Add an entry for the index .pod to cause the HTML to be generated later. |
|
332 push (@{$spec->{podFiles}}, { |
|
333 tempPodFileName => $indexPodFileName, |
|
334 htmlFileName => "$podEntry->{htmlDirName}.html" |
|
335 }); |
|
336 } |
|
337 |
|
338 # Generate a POD file for each CIF and add a line for each to the index file. |
|
339 opendir(DIR, $podEntry->{cifDirName}) or die "Error: Couldn't opendir '$podEntry->{cifDirName}' - $!\n"; |
|
340 while (defined(my $file = readdir(DIR))) { |
|
341 my $cifFileName = "$podEntry->{cifDirName}\\$file"; |
|
342 if (-f $cifFileName and ($cifFileName =~ /\.cif$/i)) { |
|
343 my $podFileName = "$tempDir\\$file"; |
|
344 $podFileName =~ s/\.cif$/\.pod/i; |
|
345 my $htmlFileName = "$podEntry->{htmlDirName}\\$file"; |
|
346 $htmlFileName =~ s/\.cif$/\.html/i; |
|
347 |
|
348 print "Reading '$cifFileName'...\n" if ($options{verbose}); |
|
349 my $cif = CommandInfoFile->New($cifFileName); |
|
350 Cif2Pod($cif, $podFileName, $htmlFileName, $indexFile, $spec->{podFiles}); |
|
351 } |
|
352 } |
|
353 closedir(DIR); |
|
354 |
|
355 if ($indexFile) { |
|
356 $indexFile->close(); |
|
357 } |
|
358 } |
|
359 } |
|
360 |
|
361 sub BuildHtml { |
|
362 my $spec = shift; |
|
363 |
|
364 my $cwd = cwd(); |
|
365 unless ($options{what} or $options{clean}) { |
|
366 chdir ($spec->{tempRoot}) or die "Error: Couldn't chdir to '$spec->{tempRoot}' - $!\n"; |
|
367 } |
|
368 |
|
369 eval { |
|
370 my $first = 1; |
|
371 foreach my $podEntry (@{$spec->{podFiles}}) { |
|
372 DoBuildHtml($podEntry->{tempPodFileName}, $podEntry->{htmlFileName}, $spec->{docRoot}, $spec->{cssFile}, $first); |
|
373 $first = 0 if ($first); |
|
374 } |
|
375 }; |
|
376 |
|
377 my $error = $@; |
|
378 chdir $cwd; |
|
379 die $@ if $@; |
|
380 } |
|
381 |
|
382 sub DoBuildHtml { |
|
383 my $podFileName = shift; |
|
384 my $htmlFileName = shift; |
|
385 my $docRoot = shift; |
|
386 my $css = shift; |
|
387 my $first = shift; |
|
388 |
|
389 my $outputFileName = "$docRoot\\$htmlFileName"; |
|
390 |
|
391 if ($options{what}) { |
|
392 print "$outputFileName\n"; |
|
393 } |
|
394 elsif ($options{clean}) { |
|
395 unlink ($outputFileName); |
|
396 } |
|
397 else { |
|
398 print "Building $outputFileName\n" if ($options{verbose}); |
|
399 fshu::MakePath(dirname($outputFileName)); |
|
400 |
|
401 my @elements = split /\\/, $htmlFileName; |
|
402 my $numElements = @elements; |
|
403 my $pathRelativeToDocRoot = '.'; |
|
404 for (my $i = 0; $i < ($numElements - 1); ++$i) { |
|
405 if ($pathRelativeToDocRoot eq '.') { |
|
406 $pathRelativeToDocRoot = '..'; |
|
407 } |
|
408 else { |
|
409 $pathRelativeToDocRoot = "..\\$pathRelativeToDocRoot"; |
|
410 } |
|
411 } |
|
412 |
|
413 my @args = ("--podpath=.", |
|
414 "--podroot=.", |
|
415 "--htmlroot=$pathRelativeToDocRoot", |
|
416 "--recurse", |
|
417 "--infile=$podFileName", |
|
418 "--outfile=$outputFileName"); |
|
419 # push (@args, '--verbose') if ($options{verbose}); |
|
420 if ($css) { |
|
421 my $relativeCssName = "$pathRelativeToDocRoot\\" . basename($css); |
|
422 push(@args, "--css=$relativeCssName"); |
|
423 } |
|
424 if ($first) { |
|
425 push (@args, '--flush'); |
|
426 } |
|
427 |
|
428 print "Calling pod2html - ", join(' ', @args), "\n" if ($options{verbose}); |
|
429 pod2html(@args); |
|
430 } |
|
431 } |
|
432 |
|
433 sub Cif2Pod { |
|
434 my $cif = shift; |
|
435 my $podFileName = shift; |
|
436 my $htmlFileName = shift; |
|
437 my $indexFile = shift; |
|
438 my $podFileList = shift; |
|
439 |
|
440 # Add an entry for the CIF .pod to cause the HTML to be generated later. |
|
441 push (@$podFileList, { |
|
442 tempPodFileName => $podFileName, |
|
443 htmlFileName => $htmlFileName |
|
444 }); |
|
445 |
|
446 if ($options{what}) { |
|
447 # Do nothing. |
|
448 } |
|
449 elsif ($options{clean}) { |
|
450 unlink ($podFileName); |
|
451 } |
|
452 else { |
|
453 open (OUTPUT, ">$podFileName") or die "Error: Couldn't open '$podFileName' for writing: $!\n"; |
|
454 |
|
455 print OUTPUT "=head1 SYNTAX\n\n"; |
|
456 my $fullName = $cif->FullName(); |
|
457 $fullName =~ s/^\S+\s//; # Remove the root command name if this is a sub-command. |
|
458 print OUTPUT ' ', $fullName; |
|
459 |
|
460 my $options = $cif->Options(); |
|
461 if ($options and (@$options > 0)) { |
|
462 print OUTPUT ' [options]'; |
|
463 } |
|
464 |
|
465 my $arguments = $cif->Arguments(); |
|
466 foreach my $argument (@$arguments) { |
|
467 if ($argument->{flags}->{optional}) { |
|
468 print OUTPUT ' [<'; |
|
469 } |
|
470 else { |
|
471 print OUTPUT ' <'; |
|
472 } |
|
473 print OUTPUT $argument->{name}; |
|
474 if ($argument->{flags}->{optional}) { |
|
475 print OUTPUT '>]'; |
|
476 } |
|
477 else { |
|
478 print OUTPUT '>'; |
|
479 } |
|
480 if ($argument->{flags}->{multiple}) { |
|
481 print OUTPUT ' ...'; |
|
482 } |
|
483 } |
|
484 print OUTPUT "\n\n"; |
|
485 |
|
486 if ($options and (@$options > 0)) { |
|
487 print OUTPUT "=head1 OPTIONS\n\n"; |
|
488 print OUTPUT "=over5\n\n"; |
|
489 foreach my $option (@$options) { |
|
490 print OUTPUT "=item -$option->{short_name} (--$option->{long_name}) $option->{type}\n\n$option->{description}"; |
|
491 if ($option->{type} eq 'enum') { |
|
492 FormatEnum($option->{enum_values}); |
|
493 } |
|
494 if ($option->{flags}->{multiple}) { |
|
495 print OUTPUT " Can be specified more than once."; |
|
496 } |
|
497 if ($option->{env_var}) { |
|
498 print OUTPUT " Can also be specified by defining the environment variable '$option->{env_var}'."; |
|
499 } |
|
500 print OUTPUT "\n\n"; |
|
501 } |
|
502 print OUTPUT "\n\n=back\n\n"; |
|
503 } |
|
504 |
|
505 if ($arguments and (@$arguments > 0)) { |
|
506 print OUTPUT "=head1 ARGUMENTS\n\n\n\n"; |
|
507 print OUTPUT "=over5\n\n"; |
|
508 foreach my $argument (@$arguments) { |
|
509 print OUTPUT '=item '; |
|
510 if ($argument->{flags}->{optional}) { |
|
511 print OUTPUT '[<'; |
|
512 } |
|
513 else { |
|
514 print OUTPUT '<'; |
|
515 } |
|
516 print OUTPUT $argument->{name}; |
|
517 if ($argument->{flags}->{optional}) { |
|
518 print OUTPUT ">]\n\n"; |
|
519 } |
|
520 else { |
|
521 print OUTPUT ">\n\n"; |
|
522 } |
|
523 print OUTPUT $argument->{description}; |
|
524 if ($argument->{flags}->{multiple}) { |
|
525 print OUTPUT ' Can be specified more than once.'; |
|
526 } |
|
527 if ($argument->{env_var}) { |
|
528 print OUTPUT " Can also be specified by defining the environment variable '$argument->{env_var}'."; |
|
529 } |
|
530 if ($argument->{flags}->{last}) { |
|
531 print OUTPUT ' Any further arguments or options will be coalesced into this one.'; |
|
532 } |
|
533 |
|
534 if ($argument->{type} eq 'enum') { |
|
535 FormatEnum($argument->{enum_values}); |
|
536 } |
|
537 elsif ($argument->{flags}->{multiple}) { |
|
538 print OUTPUT " [$argument->{type}(s)]"; |
|
539 } |
|
540 else { |
|
541 print OUTPUT " [$argument->{type}]"; |
|
542 } |
|
543 print OUTPUT "\n\n"; |
|
544 } |
|
545 print OUTPUT "\n\n=back\n\n"; |
|
546 } |
|
547 |
|
548 print OUTPUT "=head1 DESCRIPTION\n\n"; |
|
549 print OUTPUT $cif->ShortDescription(), "\n\n"; |
|
550 if ($cif->LongDescription()) { |
|
551 print OUTPUT $cif->LongDescription(), "\n\n"; |
|
552 } |
|
553 if ($cif->SeeAlso()) { |
|
554 print OUTPUT "=head1 SEE ALSO\n\n"; |
|
555 print OUTPUT $cif->SeeAlso(), "\n\n"; |
|
556 } |
|
557 |
|
558 if ($cif->NumSubCommands() > 0) { |
|
559 print OUTPUT "=head1 SUB-COMMANDS\n\n"; |
|
560 my $numSubCommands = $cif->NumSubCommands(); |
|
561 for (my $i = 0; $i < $numSubCommands; ++$i) { |
|
562 my $subCommandCif = $cif->SubCommand($i); |
|
563 my $subCommandName = $subCommandCif->Name(); |
|
564 my $subCommandPodName = $subCommandCif->FullName(); |
|
565 $subCommandPodName =~ s/ /-/g; |
|
566 print OUTPUT "L<$subCommandName|$subCommandPodName>\n\n"; |
|
567 } |
|
568 } |
|
569 |
|
570 if ($cif->Copyright()) { |
|
571 print OUTPUT "=head1 COPYRIGHT\n\n"; |
|
572 print OUTPUT $cif->Copyright(), "\n\n"; |
|
573 } |
|
574 |
|
575 close (OUTPUT); |
|
576 } |
|
577 |
|
578 if ($indexFile) { |
|
579 my $description = $cif->ShortDescription(); |
|
580 $description =~ s/^\s*//; |
|
581 $description =~ s/\s*$//; |
|
582 print $indexFile "\nL<$cif->{name}|$cif->{name}> - $description\n\n"; |
|
583 } |
|
584 |
|
585 if ($cif->NumSubCommands() > 0) { |
|
586 # Recurse through sub-commands. |
|
587 my $numSubCommands = $cif->NumSubCommands(); |
|
588 for (my $i = 0; $i < $numSubCommands; ++$i) { |
|
589 my $thisSubCommandCif = $cif->SubCommand($i); |
|
590 my $fullSubCommandName = $thisSubCommandCif->FullName(); |
|
591 $fullSubCommandName =~ s/ /-/g; |
|
592 my $podName = $podFileName; |
|
593 $podName =~ s/[^\\]+$/$fullSubCommandName\.pod/; |
|
594 my $htmlName = $htmlFileName; |
|
595 $htmlName =~ s/[^\\]+$/$fullSubCommandName\.html/; |
|
596 Cif2Pod($cif->SubCommand($i), $podName, $htmlName, undef, $podFileList); |
|
597 } |
|
598 } |
|
599 } |
|
600 |
|
601 sub FormatEnum { |
|
602 my $enumValues = shift; |
|
603 |
|
604 my $descriptionsPresent = 0; |
|
605 foreach my $enumValue (@$enumValues) { |
|
606 if ($enumValue->{description} !~ /^\s*$/) { |
|
607 $descriptionsPresent= 1; |
|
608 last; |
|
609 } |
|
610 } |
|
611 if ($descriptionsPresent) { |
|
612 print OUTPUT "\n\n=over 5\n\n"; |
|
613 foreach my $enumValue (@$enumValues) { |
|
614 print OUTPUT "=item $enumValue->{value}\n\n"; |
|
615 if ($enumValue->{description}) { |
|
616 print OUTPUT $enumValue->{description}; |
|
617 } |
|
618 } |
|
619 print OUTPUT "\n\n=back\n\n"; |
|
620 } |
|
621 else { |
|
622 local $_; |
|
623 print OUTPUT ' [', join (', ', map {$_->{value}} @$enumValues), ']'; |
|
624 } |
|
625 } |
|
626 |
|
627 __END__ |
|
628 |
|
629 =head1 NAME |
|
630 |
|
631 fsh-builddocs - A tool that generates HTML documentation from POD source files. |
|
632 |
|
633 =head1 SYNOPSIS |
|
634 |
|
635 fsh-builddocs <pod-list-file> |
|
636 |
|
637 options: |
|
638 |
|
639 -h (--help) Display this help page. |
|
640 -v (--verbose) Verbose output. |
|
641 -w (--what) Do nothing but print the names of the files that would |
|
642 be generated. |
|
643 -c (--clean) Delete target files, rather than build them. |
|
644 |
|
645 =head1 DESCRIPTION |
|
646 |
|
647 This tool accepts a list of POD files (and indices - more on them later) and generates a corresponding set of HTML files within the specified output directory. The directory structure of the POD source files is mirrored in the output directory. |
|
648 |
|
649 The C<pod-list> file is preprocessed using F<cpp.exe> and so macro directives can be used to modify the list to suit a particular build configuration. |
|
650 |
|
651 The following syntax is supported for C<pod-list> files: |
|
652 |
|
653 =over 5 |
|
654 |
|
655 =item C<doc-root E<lt>documentation_root_dirE<gt>> |
|
656 |
|
657 The directory into which the documentation HTML files will be generated. |
|
658 |
|
659 =item C<temp-root E<lt>temporary_file_root_dirE<gt>> |
|
660 |
|
661 The directory into any temporary files that are needed will be written. |
|
662 |
|
663 =item C<css E<lt>css_file_nameE<gt>> |
|
664 |
|
665 The name of a cascaded style sheet file that each of the generated HTML files should refer to. If specified, the file will be coped into the documentation root directory. |
|
666 |
|
667 =item C<pod E<lt>pod_file_nameE<gt> E<lt>html_file_nameE<gt>> |
|
668 |
|
669 Specifies a POD source file and a target HTML. The HTML file names are expected to be relative to the documentation root directory (specified with C<doc-root>). |
|
670 |
|
671 =item C<index E<lt>html_dir_nameE<gt>> [E<lt>index_pod_file_nameE<gt>] |
|
672 |
|
673 Generates a file named C<html_dir_name>F<.html>. This is produced by taking the contents of F<index_pod_file_name> (if specfied) and appending to that a links to each other HTML files that are present in the specified HTML directory. Note, because C<pod-list> files are preprocessed, it is possible to vary the contents of the index according to the build configuration by using #ifdef directives to prevent certain C<pod> lines from being active. For example: |
|
674 |
|
675 pod my_pod_dir\some_pod_that_is_always_build.pod my_html_dir\some_pod_that_is_always_built.html |
|
676 #ifdef SOME_BUILD CONFIG |
|
677 pod my_pod_dir\some_pod_that_is_only_built_sometimes.pod my_html_dir\some_pod_that_is_only_built_sometimes.html |
|
678 #endif |
|
679 index my_html_dir my_pod_dir\index.pod |
|
680 |
|
681 =item C<cif E<lt>cif_dir_nameE<gt> E<lt>html_dir_nameE<gt> [E<lt>index_pod_file_nameE<gt>]> |
|
682 |
|
683 Specifies a directory containing a set of Command Information Files (CIFs). The CIFs are converted to POD and in the temporary directory and then to HTML in the HTML directory (which is expected to be relative to the documentation root directory). In addition a page containing links to each of the CIF HTML files is generated. This is named C<html_dir_name>F<.html> and is headed with the POD from C<index_pod_file_name> if that has been specified. |
|
684 |
|
685 =back |
|
686 |
|
687 =head1 KNOWN BUGS |
|
688 |
|
689 None known. |
|
690 |
|
691 =head1 COPYRIGHT |
|
692 |
|
693 Copyright (c) 2010 Accenture. All rights reserved. |
|
694 |
|
695 =cut |