#!/usr/bin/perl -w # podwrapper.pl # Copyright (C) 2010-2012 Red Hat Inc. # @configure_input@ # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. use warnings; use strict; use Pod::Usage; use Getopt::Long; use Pod::Man; use Pod::Simple; use Pod::Simple::Text; use Pod::Simple::XHTML; use File::Basename; =encoding utf8 =head1 NAME podwrapper.pl - Generate various output formats from POD input files =head1 SYNOPSIS virt-foo.1 $(top_builddir)/html/virt-foo.1.html: stamp-virt-foo.pod stamp-virt-foo.pod: virt-foo.pod $(PODWRAPPER) --man virt-foo.1 --html virt-foo.1.html $< touch $@ =head1 DESCRIPTION podwrapper is a Perl script that generates various output formats from POD input files that libguestfs uses for most documentation. You should specify an input file, and one or more output formats. For example: podwrapper.pl virt-foo.pod --man virt-foo.1 will turn C into a man page C. The output options are I<--man>, I<--html> and I<--text> (see below). =head1 OPTIONS =over 4 =cut my $help; =item B<--help> Display brief help. =cut my $html; =item B<--html=output.html> Write a web page to C. If this option is not given, then no web page output is produced. =cut my @inserts; =item B<--insert=filename:@PATTERN@> In the input file, replace the literal text C<@PATTERN@> with the replacement file C. You can give this option multiple times. The contents of C are treated as POD. Compare and contrast with I<--verbatim>. Although it is conventional to use C<@...@> for patterns, in fact you can use any string as the pattern. =cut my $man; =item B<--man=output.n> Write a man page to C. If this option is not given, then no man page output is produced. =cut my $name; =item B<--name=name> Set the name of the man page. If not set, defaults to the basename of the input file. =cut my $section; =item B<--section=N> Set the section of the man page (a number such as C<1> for command line utilities or C<3> for C API documentation). If not set, defaults to C<1>. =cut my $text; =item B<--text=output.txt> Write a text file to C. If this option is not given, then no text output is produced. =cut my @verbatims; =item B<--verbatim=filename:@PATTERN@> In the input file, replace the literal text C<@PATTERN@> with the replacement file C. You can give this option multiple times. The contents of C are inserted as verbatim text, and are I interpreted as POD. Compare and contrast with I<--insert>. Although it is conventional to use C<@...@> for patterns, in fact you can use any string as the pattern. =cut =back =cut # Clean up the program name. my $progname = $0; $progname =~ s{.*/}{}; # Parse options. GetOptions ("help|?" => \$help, "html=s" => \$html, "insert=s" => \@inserts, "man=s" => \$man, "name=s" => \$name, "section=s" => \$section, "text=s" => \$text, "verbatim=s" => \@verbatims ) or pod2usage (2); pod2usage (1) if $help; die "$progname: missing argument: podwrapper input.pod\n" unless @ARGV == 1; my $input = $ARGV[0]; # There should be at least one output. die "$progname: no output format specified. Use --man and/or --html and/or --text.\n" unless defined $man || defined $html || defined $text; # Default for $name and $section. $name = basename ($input, ".pod") unless defined $name; $section = 1 unless defined $section; # Note that these @...@ are substituted by ./configure. my $abs_top_srcdir = "@abs_top_srcdir@"; my $abs_top_builddir = "@abs_top_builddir@"; my $package_name = "@PACKAGE_NAME@"; my $package_version = "@PACKAGE_VERSION@"; die "$progname: ./configure substitutions were not performed" unless $abs_top_srcdir && $abs_top_builddir && $package_name && $package_version; # Create a stable date (thanks Hilko Bengen). my $date; my $filename = "$abs_top_srcdir/ChangeLog"; if (-r $filename) { open FILE, $filename or die "$progname: $filename: $!"; $_ = ; close FILE; $date = $1 if /^(\d+-\d+-\d+)\s/; } $filename = "$abs_top_srcdir/.git"; if (!$date && -d $filename) { local $ENV{GIT_DIR} = $filename; $_ = `git show -s --format=%ci`; $date = $1 if /^(\d+-\d+-\d+)\s/; } if (!$date) { my ($day, $month, $year) = (localtime)[3,4,5]; $date = sprintf ("%04d-%02d-%02d", $year+1900, $month+1, $day); } # Create a release string. my $release = "$package_name-$package_version"; #print "input=$input\n"; #print "name=$name\n"; #print "section=$section\n"; #print "date=$date\n"; # Read the input. my $content = read_whole_file ($input); # Perform @inserts. foreach (@inserts) { my @a = split /:/, $_, 2; die "$progname: no colon in parameter of --insert\n" unless @a >= 2; my $replacement = read_whole_file ($a[0]); $content =~ s/$a[1]/$replacement/ge; } # Perform @verbatims. foreach (@verbatims) { my @a = split /:/, $_, 2; die "$progname: no colon in parameter of --verbatim\n" unless @a >= 2; my $replacement = read_verbatim_file ($a[0]); $content =~ s/$a[1]/$replacement/ge; } # Output man page. SUBMAN: { package Podwrapper::Man; use vars qw(@ISA $VERSION); @ISA = qw(Pod::Man); $VERSION = $package_version; # Override the L<> method. sub cmd_l { my ($self, $attrs, $text) = @_; return $text; } } if ($man) { my $parser = Podwrapper::Man->new ( name => $name, release => $release, section => $section, center => "Virtualization Support", date => $date, stderr => 1, utf8 => 1 ); my $output; $parser->output_string (\$output); $parser->parse_string_document ($content) or die "$progname: could not parse input document"; open OUT, ">$man" or die "$progname: $man: $!"; print OUT $output or die "$progname: $man: $!"; close OUT or die "$progname: $man: $!"; print "$progname: wrote $man\n"; } # Output HTML. SUBHTML: { # Subclass Pod::Simple::XHTML. See the documentation. package Podwrapper::XHTML; use vars qw(@ISA $VERSION); @ISA = qw(Pod::Simple::XHTML); $VERSION = $package_version; # Pod::Simple::XHTML returns uppercase identifiers, whereas the # old pod2html returns lowercase ones. sub idify { my $self = shift; my $id = $self->SUPER::idify (@_); lc ($id); } sub is_a_libguestfs_page { local $_ = shift; return 1 if /^Sys::Guestfs/; return 1 if /^virt-/; return 1 if /^libguestf/; return 1 if /^guestf/; return 1 if /^guestmount/; return 1 if /^hivex/; return 1 if /^febootstrap/; return 0; } sub resolve_pod_page_link { my $self = shift; my $podname = $_[0]; # eg. "Sys::Guestfs", can be undef my $anchor = $_[1]; # eg. "SYNOPSIS", can be undef my $r = ""; if (defined $podname) { return $self->SUPER::resolve_pod_page_link (@_) unless is_a_libguestfs_page ($podname); $r .= "$podname.3.html" } $r .= "#" . $self->idify ($anchor, 1) if defined $anchor; $r; } sub resolve_man_page_link { my $self = shift; my $name = $_[0]; # eg. "virt-make-fs(1)", can be undef my $anchor = $_[1]; # eg. "SYNOPSIS", can be undef my $r = ""; if (defined $name) { return $self->SUPER::resolve_man_page_link (@_) unless is_a_libguestfs_page ($name); $name =~ s/\((.*)\)$/.$1/; $r .= "$name.html"; } $r .= "#" . $self->idify ($anchor, 1) if defined $anchor; $r; } } if ($html) { mkdir "$abs_top_builddir/html"; my $parser = Podwrapper::XHTML->new; my $output; $parser->output_string (\$output); $parser->html_charset ("UTF-8"); $parser->html_css ("pod.css"); $parser->index (1); $parser->parse_string_document ($content); # Hack for Perl 5.16. $output =~ s{/>pod.css<}{/>\n<}; open OUT, ">$html" or die "$progname: $html: $!"; print OUT $output or die "$progname: $html: $!"; close OUT or die "$progname: $html: $!"; print "$progname: wrote $html\n"; } # Output text. if ($text) { my $parser = Pod::Simple::Text->new; my $output; $parser->output_string (\$output); $parser->parse_string_document ($content); open OUT, ">$text" or die "$progname: $text: $!"; print OUT $output or die "$progname: $text: $!"; close OUT or die "$progname: $text: $!"; print "$progname: wrote $text\n"; } sub read_whole_file { my $input = shift; local $/ = undef; open FILE, $input or die "$progname: $input: $!"; $_ = ; close FILE; $_; } sub read_verbatim_file { my $input = shift; my $r = ""; open FILE, $input or die "$progname: $input: $!"; while () { $r .= " $_"; } close FILE; $r; } =head1 AUTHOR Richard W.M. Jones. =head1 SEE ALSO libguestfs.git/README, L