3 package Local::MkManPages;
7 use File::Basename qw(basename);
9 use Getopt::Long qw(GetOptionsFromArray);
10 use Pod::Usage qw(pod2usage);
11 use Pod::Simple::XHTML;
13 __PACKAGE__->run(@ARGV);
15 sub Releases { return (qw(master 1.1.1 1.1.0 1.0.2)) }
16 sub Dirs { return (qw(apps crypto ssl
17 man1 man3 man5 man7)) }
18 sub Dir2Section { return ( apps => "man1", crypto => "man3", ssl => "man3" ) }
21 my ( $class, $ver ) = @_;
22 my %known = map { $_ => 1 } $class->Releases;
23 return @_ != 2 ? %known : defined $known{$ver} ? $ver : undef;
27 my ( $class, @argv ) = @_;
28 my $opt = $class->process_options(@argv);
29 $class->cleanup( $opt->{WwwDir}, $opt->{RelVer} );
30 exit $class->main( $opt->{SrcDir}, $opt->{WwwDir}, $opt->{RelVer} );
34 my ( $class, $srcdir, $wwwdir, $release ) = @_;
36 foreach my $subdir ( $class->Dirs ) {
37 my $dir = File::Spec->catfile( $srcdir, $subdir );
38 if ( opendir( my $dh, $dir ) ) {
39 while ( my $ent = readdir($dh) ) {
40 next if $ent =~ /^\./;
41 next if $ent !~ /\.pod$/;
43 my $origbase = basename( $ent, ".pod" );
44 my $title = $origbase;
45 my $tmp_sect = { $class->Dir2Section }->{$subdir} // $subdir;
46 (my $tmp_sectnum = $tmp_sect) =~ s|^man||;
47 # In addition to what getdata() gives us, we add a few
48 # defaults of our own:
51 # subdir => "..." # The original subdir
52 # sect => "..." # Output section subdir
53 # sectnum => n # Default section number
58 sectnum => $tmp_sectnum,
59 $class->getdata( File::Spec->catfile ( $dir, $ent ) )
61 # These are for display
62 my $podfile = File::Spec->catfile( $subdir, $ent );
63 my $incfile = File::Spec->catfile( $data{sect},
65 # These are files we're actually manipulating
66 my $inpod = File::Spec->catfile( $srcdir, $podfile );
67 my $outinc = File::Spec->catfile( $wwwdir, $incfile );
69 # Get main HTML output
70 my $out = $class->geninc( $release, $inpod, %data );
71 open( my $fh, ">", $outinc )
72 or $class->die("Can't open $outinc: $!");
73 print $fh $out or $class->die("Can't print $outinc: $!");
74 close($fh) or $class->die("Can't close $outinc: $!");
76 foreach my $htmlname (@{$data{names}}) {
77 my $htmlfile = File::Spec->catdir( $data{sect},
79 my $outhtml = File::Spec->catfile( $wwwdir, $htmlfile );
80 $out = $class->genhtml( $release, $title, $origbase,
82 open( $fh, ">", $outhtml )
83 or $class->die("Can't open $outhtml: $!");
84 print $fh $out or $class->die("Can't print $outhtml: $!");
85 close($fh) or $class->die("Can't close $outhtml: $!");
92 # Generate manpag HTML wrapper
94 my ( $class, $release, $title, $origbase, $htmlbase, %data ) = @_;
98 <!-- OSSL: original subdir: $data{subdir} -->
99 <!-- OSSL: subdir: $data{sect} -->
100 <!-- OSSL: section: $data{sectnum} -->
101 <!-- OSSL: description: $data{description} -->
102 <!--#include virtual="/inc/head.shtml" -->
104 <!--#include virtual="/inc/banner.shtml" -->
107 <div class="blog-index">
109 <header><h2>$title</h2></header>
110 <div class="entry-content">
112 <!--#include virtual="$origbase.inc" -->
116 You are here: <a href="/">Home</a>
117 : <a href="/docs">Docs</a>
118 : <a href="/docs/manpages.html">Manpages</a>
119 : <a href="/docs/man$release/">$release</a>
120 : <a href="/docs/man$release/$data{sect}">$data{sect}</a>
121 : <a href="/docs/man$release/$data{sect}/$htmlbase.html">$htmlbase</a>
122 <br/><a href="/sitemap.txt">Sitemap</a>
126 <aside class="sidebar">
128 <h1><a href="/docs/man$release/">$release manpages</a></h1>
130 <li><a href="../man1">Commands</a></li>
131 <li><a href="../man3">Libraries</a></li>
132 <li><a href="../man5">File Formats</a></li>
133 <li><a href="../man7">Overviews</a></li>
136 <!--#include virtual="$htmlbase.cross" -->
140 <!--#include virtual="/inc/footer.shtml" -->
146 # Generate manpage content
148 my ( $class, $release, $filename, %data ) = @_;
150 open( my $fh, $filename ) or $class->die("Can't open $filename: $!");
151 my $infile = do { local $/; <$fh>; };
154 # L<asdf...|qwer...> ==> L<qwer>
155 $infile =~ s/L<[^|>]*\|([^>]+)>/L<$1>/g;
157 # L<asdf(x)> --> L<asdf>
158 $infile =~ s/L<([^>]+)\(\d\)>/L<$1>/g;
161 my $pod = Pod::Simple::XHTML->new;
162 $pod->html_h_level(3);
163 $pod->perldoc_url_prefix("/docs/man$release/$data{sect}/");
164 $pod->perldoc_url_postfix(".html");
165 $pod->man_url_prefix("/docs/man$release/$data{sect}/");
166 $pod->man_url_postfix(".html");
167 $pod->html_header('');
168 $pod->html_footer('');
169 $pod->output_string( \$out );
170 $pod->parse_string_document($infile);
174 # Return diverse data from a manpage if available, currently:
176 # names => [ ... ] # list of all OTHER names
177 # description => "text" # the short description from NAME
178 # section => n # the section number
181 my ( $class, $infile ) = @_;
183 open( my $fh, "<", $infile ) or $class->die("Can't open $infile: $!");
190 if (/^=for comment openssl_manual_section:\s*(\d+)/) {
191 $data{sectnum} = "$1";
192 $data{sect} = "man$1";
194 elsif (/^=head1\s/) {
199 $data{description} = $';
206 push @{$data{names}}, split ',';
209 if (/^=head1\s+NAME\s*$/) {
225 my $prog = basename($0);
226 warn("$prog: $_\n") for @_;
229 # Remove all files from a manpage subtree, and leave only
230 # the index and the section subdirs.
232 my ( $class, $wwwdir, $release ) = @_;
233 my $idx = File::Spec->catfile( $wwwdir, "index.html" );
236 mkdir($wwwdir) or $class->die("mkdir '$wwwdir': $!");
239 # TBD: was $class->die
240 $class->error("No $idx") unless ( -f $idx );
241 foreach my $subdir ( $class->Dirs ) {
242 my $realsubdir = { $class->Dir2Section }->{$subdir} // $subdir;
243 my $realsdir = File::Spec->catfile( $wwwdir, $realsubdir );
244 if ( !-d $realsdir ) {
245 mkdir($realsdir) or $class->die("mkdir '$realsdir': $!");
249 my $sdir = File::Spec->catfile( $wwwdir, $subdir );
251 opendir( my $dh, $sdir ) or $class->die("opendir '$sdir': $!");
252 while ( my $ent = readdir($dh) ) {
253 next if $ent =~ /^\./;
254 next if $realsdir eq $sdir && $ent =~ /^index.(?:html|inc)$/;
255 my $f = File::Spec->catfile( $sdir, $ent );
256 unlink($f) or $class->error("Can't unlink '$f': $!");
260 if ( $realsubdir ne $subdir ) {
267 sub process_options {
268 my ( $class, @argv ) = @_;
271 GetOptionsFromArray( \@argv, \%opt, "help", "man" )
272 or pod2usage( -verbose => 0 );
274 pod2usage( -verbose => 1 ) if ( $opt{help} or @argv != 3 );
275 pod2usage( -verbose => 2 ) if ( $opt{man} );
277 # <src/dir> <rel.ver> <www/dir>
278 my @argkeys = qw(SrcDir RelVer WwwDir);
279 @opt{@argkeys} = @argv;
281 # no empty values, directories must exist
283 foreach my $key (@argkeys) {
284 push( @err, "Invalid $key argument '$opt{$key}'" )
285 if ( $opt{$key} =~ /^\s*$/ );
286 push( @err, "Directory '$opt{$key}': $!" )
287 if ( $key =~ /Dir$/ and !-d $opt{$key} );
289 $class->die(@err) if @err;
291 # each source dir has a set of subdirs with documentation
293 my $docdir = File::Spec->catfile( $opt{SrcDir} );
294 foreach my $subdir ( $class->Dirs ) {
295 my $dir = File::Spec->catfile( $docdir, $subdir );
296 push @found_dirs, $dir if -d $dir;
298 push( @err, "No documentation directories in $docdir" )
299 unless ( @found_dirs );
302 push( @err, "Unknown release '$opt{RelVer}'" )
303 unless ( $class->getRelease( $opt{RelVer} ) );
304 $class->die(@err) if @err;
315 mk-manpages - htmlize man pages from POD for the OpenSSL website
319 mk-manpages [options] <SrcDir> <RelVer> <WwwDir>
321 <SrcDir> doc directory of release <RelVer>, example 'OpenSSL_1_0_2-stable/doc'
322 <RelVer> version number associated with <SrcDir>, example '1.0.2'
323 <WwwDir> top level directory beneath which generated html is stored, example 'web'
325 --help display a brief help message
326 --man display full documentation
330 This utility is run on a web server generate the htmlized version of
331 OpenSSL documentation from the original POD. The resultant directory
332 structure may look something like the following (where the contents of
333 index.html do not come from this tool):
335 $ ls some/path/to/web
336 man1.0.2 man1.1.0 manmaster
337 $ ls some/path/to/web/man1.0.2
338 apps crypto index.html ssl
339 $ ls some/path/to/web/man1.0.2/apps