4 # Copyright (C) 2010-2021 Red Hat Inc.
6 # Redistribution and use in source and binary forms, with or without
7 # modification, are permitted provided that the following conditions are
10 # * Redistributions of source code must retain the above copyright
11 # notice, this list of conditions and the following disclaimer.
13 # * Redistributions in binary form must reproduce the above copyright
14 # notice, this list of conditions and the following disclaimer in the
15 # documentation and/or other materials provided with the distribution.
17 # * Neither the name of Red Hat nor the names of its contributors may be
18 # used to endorse or promote products derived from this software without
19 # specific prior written permission.
21 # THIS SOFTWARE IS PROVIDED BY RED HAT AND CONTRIBUTORS ''AS IS'' AND
22 # ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
23 # THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
24 # PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL RED HAT OR
25 # CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
26 # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
27 # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
28 # USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
29 # ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
30 # OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
31 # OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
38 #$SIG{ __DIE__ } = sub { Carp::confess( @_ ) };
44 use Pod
::Simple
::Text
;
45 use Pod
::Simple
::XHTML
;
48 # https://www.redhat.com/archives/libguestfs/2013-May/thread.html#00088
49 eval { $Text::Wrap
::huge
= "overflow" };
51 # All man page names must match this function.
52 sub validate_name_field
58 # The license for man pages in this package - see LICENSE below.
59 my $package_license = "bsd";
63 podwrapper.pl - generate documentation from POD input files
72 CLEANFILES += $(man_MANS)
75 $(PODWRAPPER) --section 1 --man $@ \
76 --html $(top_builddir)/html/$@.html \
83 podwrapper.pl is a Perl script that generates various output formats
84 from POD input files that this project uses for most documentation.
86 You must specify one input file, and one or more output formats. The
87 output options are I<--man>, I<--html> and I<--text> (see below).
89 In C<Makefile.am> files, use a variation of the boilerplate shown in
90 the L</SYNOPSIS> section above.
92 For information about the POD format, see L<perlpod(1)>.
108 my $allow_long_lines;
110 =item B<--allow-long-lines>
112 Allow lines longer than 76 characters in the input. Use this
113 if the man page is not written by hand.
119 =item B<--html> output.html
121 Write a web page to F<output.html>. If this option is not
122 given, then no web page output is produced.
128 =item B<--insert> filename:__PATTERN__
130 In the input file, replace the literal text C<__PATTERN__> with the
131 replacement file F<filename>. You can give this option multiple
134 The contents of F<filename> are treated as POD.
135 Compare and contrast with I<--verbatim>.
137 Although it is conventional to use C<__...__> (double underscores) for
138 patterns, in fact you can use any string as the pattern.
144 =item B<--man> output.n
146 Write a man page to F<output.n> (C<n> is the manual section number).
147 If this option is not given, then no man page output is produced.
155 Set the name of the man page. If not set, defaults to the basename
164 Set the section of the man page (a number such as C<1> for
165 command line utilities or C<3> for C API documentation). If
166 not set, defaults to C<1>.
172 =item B<--text> output.txt
174 Write a text file to F<output.txt>. If this option is not
175 given, then no text output is produced.
181 =item B<--verbatim> filename:__PATTERN__
183 In the input file, replace the literal text C<__PATTERN__> with the
184 replacement file F<filename>. You can give this option multiple
187 The contents of F<filename> are inserted as verbatim text, and
188 are I<not> interpreted as POD.
189 Compare and contrast with I<--insert>.
191 Although it is conventional to use C<__...__> (double underscores) for
192 patterns, in fact you can use any string as the pattern.
196 # Clean up the program name.
198 $progname =~ s{.*/}{};
201 GetOptions
("help|?" => \
$help,
202 "allow-long-lines" => \
$allow_long_lines,
204 "insert=s" => \
@inserts,
207 "section=s" => \
$section,
209 "verbatim=s" => \
@verbatims,
211 pod2usage
(1) if $help;
213 die "$progname: missing argument: podwrapper input.pod\n" unless @ARGV == 1;
214 my $input = $ARGV[0];
216 # There should be at least one output.
217 die "$progname: $input: no output format specified. Use --man and/or --html and/or --text.\n"
218 unless defined $man || defined $html || defined $text;
220 # Default for $name and $section.
221 $name = basename
($input, ".pod") unless defined $name;
222 $section = 1 unless defined $section;
224 # Note that these @...@ are substituted by ./configure.
225 my $abs_top_srcdir = "@abs_top_srcdir@";
226 my $abs_top_builddir = "@abs_top_builddir@";
227 my $package_name = "@PACKAGE_NAME@";
228 my $package_version = "@PACKAGE_VERSION@";
230 die "$progname: ./configure substitutions were not performed"
231 unless $abs_top_srcdir && $abs_top_builddir &&
232 $package_name && $package_version;
234 # Create a stable date (thanks Hilko Bengen).
236 my $filename = "$abs_top_srcdir/.git";
237 if (!$date && -d
$filename) {
238 local $ENV{GIT_DIR
} = $filename;
239 $date = `git show -O/dev/null -s --format=format:%cs`;
242 my ($day, $month, $year) = (gmtime($ENV{SOURCE_DATE_EPOCH
} || time))[3,4,5];
243 $date = sprintf ("%04d-%02d-%02d", $year+1900, $month+1, $day);
246 # Create a release string.
247 my $release = "$package_name-$package_version";
249 #print "input=$input\n";
250 #print "name=$name\n";
251 #print "section=$section\n";
252 #print "date=$date\n";
255 my $content = read_whole_file
($input);
259 my @a = split /:/, $_, 2;
260 die "$progname: $input: no colon in parameter of --insert\n" unless @a >= 2;
261 my $replacement = read_whole_file
($a[0]);
262 my $oldcontent = $content;
263 $content =~ s/$a[1]/$replacement/ge;
264 die "$progname: $input: could not find pattern '$a[1]' in input file\n"
265 if $content eq $oldcontent;
268 # Turn external links to this man page into simple cross-section links.
269 $content =~ s
,\QL
<$name($section)/\E,L</,g
;
271 # Perform @verbatims.
272 foreach (@verbatims) {
273 my @a = split /:/, $_, 2;
274 die "$progname: $input: no colon in parameter of --verbatim\n" unless @a >= 2;
275 my $replacement = read_verbatim_file
($a[0]);
276 my $oldcontent = $content;
277 $content =~ s/$a[1]/$replacement/ge;
278 die "$progname: $input: could not find pattern '$a[1]' in input file\n"
279 if $content eq $oldcontent;
282 # Check the content is valid UTF8.
283 die "$progname: $input: is not valid utf8" unless utf8
::is_utf8
($content);
285 # There should be no =encoding line present in the content.
286 die "$progname: $input: =encoding must not be present in input\n"
287 if $content =~ /^=encoding/m;
289 # Don't permit trailing whitespace.
290 die "$progname: $input: trailing whitespace in input\n"
291 if $content =~ /[ \t]$/m;
293 # We may add an encoding line, but this breaks RHEL 6-era Pod::Simple
294 # with the error "Cannot decode string with wide characters".
295 $content =~ s/^=(.*)/\n=encoding utf8\n\n=$1/m
296 if $] >= 5.011; # Perl >= 5.11
298 # Verify sections present / not present.
299 die "$progname: $input: missing NAME section\n"
300 if $content !~ /^=head1 NAME/m;
301 die "$progname: $input: missing DESCRIPTION section\n"
302 if $content !~ /^=head1 DESCRIPTION/m;
303 die "$progname: $input: missing AUTHOR or AUTHORS section\n"
304 unless $content =~ /^=head1 AUTHOR/m;
305 die "$progname: $input: missing SEE ALSO section\n"
306 unless $content =~ /^=head1 SEE ALSO/m;
307 die "$progname: $input: missing COPYRIGHT section\n"
308 unless $content =~ /^=head1 COPYRIGHT/m;
309 die "$progname: $input: BUGS is now added automatically, do not add it to the POD file\n"
310 if $content =~ /^=head1 (REPORTING )?BUGS/m;
311 die "$progname: $input: LICENSE is now added automatically, do not add it to the POD file\n"
312 if $content =~ /^=head1 LICENSE/m;
314 # Check NAME section conformity.
315 my @lines = split /\n/, $content;
318 push @name, $_ if /^=head1 NAME/../^=head1 (?!NAME)/
320 shift @name; # remove =head1 and empty line
321 shift @name; # from beginning and end
324 die "$progname: $input: empty NAME section\n"
326 die "$progname: $input: NAME doesn't start with $package_name\n"
327 unless validate_name_field
($name[0]);
328 die "$progname: $input: NAME does not conform with Linux man pages standard\n"
329 if $name[0] !~ m/- [a-z]/ || $name[@name-1] =~ m/\.$/;
331 # Add standard LICENSE section at the end.
332 my $license_lgplv2plus = "\
333 This library is free software; you can redistribute it and/or
334 modify it under the terms of the GNU Lesser General Public
335 License as published by the Free Software Foundation; either
336 version 2 of the License, or (at your option) any later version.
338 This library is distributed in the hope that it will be useful,
339 but WITHOUT ANY WARRANTY; without even the implied warranty of
340 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
341 Lesser General Public License for more details.
343 You should have received a copy of the GNU Lesser General Public
344 License along with this library; if not, write to the Free Software
345 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
349 Redistribution and use in source and binary forms, with or without
350 modification, are permitted provided that the following conditions are
357 Redistributions of source code must retain the above copyright
358 notice, this list of conditions and the following disclaimer.
362 Redistributions in binary form must reproduce the above copyright
363 notice, this list of conditions and the following disclaimer in the
364 documentation and/or other materials provided with the distribution.
368 Neither the name of Red Hat nor the names of its contributors may be
369 used to endorse or promote products derived from this software without
370 specific prior written permission.
374 THIS SOFTWARE IS PROVIDED BY RED HAT AND CONTRIBUTORS ''AS IS'' AND
375 ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
376 THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
377 PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL RED HAT OR
378 CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
379 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
380 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
381 USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
382 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
383 OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
384 OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
388 $content .= "\n=head1 LICENSE\n";
389 $content .= eval "\$license_$package_license";
391 @lines = split /\n/, $content;
392 unless ($allow_long_lines) {
393 # Check no over-long lines in the input. (As a special exception
394 # this is permitted in verbatim sections or if the line contains a
397 die "$progname: $input: line too long:\n$_\n"
399 substr ($_, 0, 1) ne ' ' &&
404 # Check cross-references to other nbdkit man pages exist.
405 my @xrefs = $content =~ /L<(nbdkit-.*?\([1-9]\))>/g;
407 # Plugins can be in section 1 or 3. Here we only check the plugin
408 # name exists, but we should check the section (XXX).
409 if (m/^nbdkit-(.*?)-plugin\(([13])\)$/) {
412 die "$progname: $input: cannot find cross reference for $_\n"
413 if ! -d
"$abs_top_srcdir/plugins/$name"
415 # All filters should be in section 1, so we only need to check
417 elsif (m/^nbdkit-(.*?)-filter\(1\)$/) {
419 die "$progname: $input: cannot find cross reference for $_\n"
420 if ! -d
"$abs_top_srcdir/filters/$name"
422 # Other documentation in section 1.
423 elsif (m/^nbdkit-(.*)\(1\)$/) {
425 die "$progname: $input: cannot find cross reference for $_\n"
426 if ! -f
"$abs_top_srcdir/docs/nbdkit-$name.pod"
428 elsif (m/^nbdkit-plugin\(3\)$/ || m/^nbdkit-filter\(3\)$/) {
432 die "$progname: $input: cannot find cross-reference for $_\n"
438 package Podwrapper
::Man
;
440 use vars
qw(@ISA $VERSION);
442 $VERSION = $package_version;
444 # Override the L<> method.
447 my ($self, $attrs, $text) = @_;
453 my $parser = Podwrapper
::Man
->new (
455 release
=> $release, section
=> $section,
456 center
=> uc $package_name,
458 stderr
=> 1, utf8
=> 1
461 $parser->no_errata_section (1);
462 $parser->complain_stderr (1);
463 $parser->output_string (\
$output);
464 $parser->parse_string_document ($content)
465 or die "$progname: could not parse input document";
466 open OUT
, ">$man" or die "$progname: $man: $!";
467 print OUT
$output or die "$progname: $man: $!";
468 close OUT
or die "$progname: $man: $!";
469 if ($parser->any_errata_seen) {
471 die "$input: errors or warnings in this POD file, see messages above\n"
473 #print "$progname: wrote $man\n";
478 # Subclass Pod::Simple::XHTML. See the documentation.
479 package Podwrapper
::XHTML
;
481 use vars
qw(@ISA $VERSION);
482 @ISA = qw(Pod::Simple::XHTML);
483 $VERSION = $package_version;
485 # Note this also allows links to related projects because they all
486 # appear together under the http://libguestfs.org website.
491 return 1 if /^Sys::Guestfs/;
492 return 0 if /^virt-install/;
493 return 1 if /^virt-/;
494 return 1 if /^libguestf/;
495 return 1 if /^guestf/;
496 return 1 if /^guestmount/;
497 return 1 if /^guestunmount/;
498 return 1 if /^hivex/;
499 return 1 if /^supermin/;
500 return 1 if /^libnbd/;
505 sub resolve_man_page_link
508 my $name = $_[0]; # eg. "foobar(3)", can be undef
509 my $anchor = $_[1]; # eg. "SYNOPSIS", can be undef
512 return $self->SUPER::resolve_man_page_link
(@_)
513 unless is_a_local_page
($name);
514 $name =~ s/\((.*)\)$/.$1/;
517 $r .= "#" . $self->idify ($anchor, 1) if defined $anchor;
523 mkdir "$abs_top_builddir/html";
525 my $parser = Podwrapper
::XHTML
->new;
527 $parser->no_errata_section (1);
528 $parser->complain_stderr (1);
529 $parser->force_title ($name[0]); # from @name above
530 $parser->output_string (\
$output);
531 # Added in Pod::Simple 3.16, 2011-03-14.
532 eval { $parser->html_charset ("UTF-8") };
533 $parser->html_css ("pod.css");
535 $parser->parse_string_document ($content);
537 # Hack for Perl 5.16.
538 $output =~ s{/>pod.css<}{/>\n<};
540 open OUT
, ">$html" or die "$progname: $html: $!";
541 print OUT
$output or die "$progname: $html: $!";
542 close OUT
or die "$progname: $html: $!";
543 if ($parser->any_errata_seen) {
545 die "$input: errors or warnings in this POD file, see messages above\n"
547 #print "$progname: wrote $html\n";
552 my $parser = Pod
::Simple
::Text
->new;
554 $parser->no_errata_section (1);
555 $parser->complain_stderr (1);
556 $parser->output_string (\
$output);
557 $parser->parse_string_document ($content);
558 open OUT
, ">$text" or die "$progname: $text: $!";
559 binmode OUT
, ":utf8";
560 print OUT
$output or die "$progname: $text: $!";
561 close OUT
or die "$progname: $text: $!";
562 if ($parser->any_errata_seen) {
564 die "$input: errors or warnings in this POD file, see messages above\n"
566 #print "$progname: wrote $text\n";
574 open FILE
, "<:encoding(UTF-8)", $input or die "$progname: $input: $!";
580 sub read_verbatim_file
585 open FILE
, "<:encoding(UTF-8)", $input or die "$progname: $input: $!";
588 if (length) { push @r, " $_" } else { push @r, "" }
591 return join ("\n", @r) . "\n";
605 Copyright (C) 2010-2021 Red Hat Inc.