xref: /openbsd-src/gnu/usr.bin/texinfo/doc/help2man (revision c0141d96fc42c7c9582a0ce613dfa6b5bbdf558f)
11cc83814Sespie#!/usr/local/bin/perl -w
21cc83814Sespie
31cc83814Sespie# Generate a short man page from --help and --version output.
43fb98d4aSespie# Copyright � 1997, 1998, 1999, 2000 Free Software Foundation, Inc.
51cc83814Sespie
61cc83814Sespie# This program is free software; you can redistribute it and/or modify
71cc83814Sespie# it under the terms of the GNU General Public License as published by
81cc83814Sespie# the Free Software Foundation; either version 2, or (at your option)
91cc83814Sespie# any later version.
101cc83814Sespie
111cc83814Sespie# This program is distributed in the hope that it will be useful,
121cc83814Sespie# but WITHOUT ANY WARRANTY; without even the implied warranty of
131cc83814Sespie# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
141cc83814Sespie# GNU General Public License for more details.
151cc83814Sespie
161cc83814Sespie# You should have received a copy of the GNU General Public License
171cc83814Sespie# along with this program; if not, write to the Free Software Foundation,
181cc83814Sespie# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
191cc83814Sespie
201cc83814Sespie# Written by Brendan O'Dea <bod@compusol.com.au>
213fb98d4aSespie# Available from ftp://ftp.gnu.org/gnu/help2man/
221cc83814Sespie
231cc83814Sespieuse 5.004;
241cc83814Sespieuse strict;
251cc83814Sespieuse Getopt::Long;
261cc83814Sespieuse Text::Tabs qw(expand);
271cc83814Sespieuse POSIX qw(strftime setlocale LC_TIME);
281cc83814Sespie
291cc83814Sespiemy $this_program = 'help2man';
303fb98d4aSespiemy $this_version = '1.24';
311cc83814Sespiemy $version_info = <<EOT;
323fb98d4aSespieGNU $this_program $this_version
331cc83814Sespie
343fb98d4aSespieCopyright (C) 1997, 1998, 1999, 2000 Free Software Foundation, Inc.
351cc83814SespieThis is free software; see the source for copying conditions.  There is NO
361cc83814Sespiewarranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
371cc83814Sespie
381cc83814SespieWritten by Brendan O'Dea <bod\@compusol.com.au>
391cc83814SespieEOT
401cc83814Sespie
411cc83814Sespiemy $help_info = <<EOT;
421cc83814Sespie`$this_program' generates a man page out of `--help' and `--version' output.
431cc83814Sespie
441cc83814SespieUsage: $this_program [OPTION]... EXECUTABLE
451cc83814Sespie
461cc83814Sespie -n, --name=STRING       use `STRING' as the description for the NAME paragraph
471cc83814Sespie -s, --section=SECTION   use `SECTION' as the section for the man page
481cc83814Sespie -i, --include=FILE      include material from `FILE'
491cc83814Sespie -I, --opt-include=FILE  include material from `FILE' if it exists
501cc83814Sespie -o, --output=FILE       send output to `FILE'
511cc83814Sespie -N, --no-info           suppress pointer to Texinfo manual
521cc83814Sespie     --help              print this help, then exit
533fb98d4aSespie     --version           print version number, then exit
541cc83814Sespie
551cc83814SespieEXECUTABLE should accept `--help' and `--version' options.
563fb98d4aSespie
573fb98d4aSespieReport bugs to <bug-help2man\@gnu.org>.
581cc83814SespieEOT
591cc83814Sespie
601cc83814Sespiemy $section = 1;
613fb98d4aSespiemy ($opt_name, @opt_include, $opt_output, $opt_no_info);
623fb98d4aSespiemy %opt_def = (
633fb98d4aSespie    'n|name=s'		=> \$opt_name,
643fb98d4aSespie    's|section=s'	=> \$section,
653fb98d4aSespie    'i|include=s'	=> sub { push @opt_include, [ pop, 1 ] },
663fb98d4aSespie    'I|opt-include=s'	=> sub { push @opt_include, [ pop, 0 ] },
673fb98d4aSespie    'o|output=s'	=> \$opt_output,
683fb98d4aSespie    'N|no-info'		=> \$opt_no_info,
693fb98d4aSespie);
701cc83814Sespie
711cc83814Sespie# Parse options.
721cc83814SespieGetopt::Long::config('bundling');
733fb98d4aSespieGetOptions (%opt_def,
741cc83814Sespie    help    => sub { print $help_info; exit },
751cc83814Sespie    version => sub { print $version_info; exit },
761cc83814Sespie) or die $help_info;
771cc83814Sespie
781cc83814Sespiedie $help_info unless @ARGV == 1;
791cc83814Sespie
801cc83814Sespiemy %include = ();
813fb98d4aSespiemy %append = ();
823fb98d4aSespiemy @include = (); # retain order given in include file
833fb98d4aSespie
843fb98d4aSespie# Provide replacement `quote-regex' operator for pre-5.005.
853fb98d4aSespieBEGIN { eval q(sub qr { '' =~ $_[0]; $_[0] }) if $] < 5.005 }
861cc83814Sespie
871cc83814Sespie# Process include file (if given).  Format is:
881cc83814Sespie#
891cc83814Sespie#   [section name]
901cc83814Sespie#   verbatim text
913fb98d4aSespie#
923fb98d4aSespie# or
933fb98d4aSespie#
943fb98d4aSespie#   /pattern/
953fb98d4aSespie#   verbatim text
963fb98d4aSespie#
971cc83814Sespie
983fb98d4aSespiewhile (@opt_include)
991cc83814Sespie{
1003fb98d4aSespie    my ($inc, $required) = @{shift @opt_include};
1013fb98d4aSespie
1023fb98d4aSespie    next unless -f $inc or $required;
1033fb98d4aSespie    die "$this_program: can't open `$inc' ($!)\n"
1043fb98d4aSespie	unless open INC, $inc;
1053fb98d4aSespie
1063fb98d4aSespie    my $key;
1073fb98d4aSespie    my $hash = \%include;
1081cc83814Sespie
1091cc83814Sespie    while (<INC>)
1101cc83814Sespie    {
1113fb98d4aSespie	# [section]
1121cc83814Sespie	if (/^\[([^]]+)\]/)
1131cc83814Sespie	{
1143fb98d4aSespie	    $key = uc $1;
1153fb98d4aSespie	    $key =~ s/^\s+//;
1163fb98d4aSespie	    $key =~ s/\s+$//;
1173fb98d4aSespie	    $hash = \%include;
1183fb98d4aSespie	    push @include, $key unless $include{$key};
1191cc83814Sespie	    next;
1201cc83814Sespie	}
1211cc83814Sespie
1223fb98d4aSespie	# /pattern/
1233fb98d4aSespie	if (m!^/(.*)/([ims]*)!)
1243fb98d4aSespie	{
1253fb98d4aSespie	    my $pat = $2 ? "(?$2)$1" : $1;
1261cc83814Sespie
1273fb98d4aSespie	    # Check pattern.
1283fb98d4aSespie	    eval { $key = qr($pat) };
1293fb98d4aSespie	    if ($@)
1303fb98d4aSespie	    {
1313fb98d4aSespie		$@ =~ s/ at .*? line \d.*//;
1323fb98d4aSespie		die "$inc:$.:$@";
1333fb98d4aSespie	    }
1343fb98d4aSespie
1353fb98d4aSespie	    $hash = \%append;
1363fb98d4aSespie	    next;
1373fb98d4aSespie	}
1383fb98d4aSespie
1393fb98d4aSespie	# Check for options before the first section--anything else is
1403fb98d4aSespie	# silently ignored, allowing the first for comments and
1413fb98d4aSespie	# revision info.
1423fb98d4aSespie	unless ($key)
1433fb98d4aSespie	{
1443fb98d4aSespie	    # handle options
1453fb98d4aSespie	    if (/^-/)
1463fb98d4aSespie	    {
1473fb98d4aSespie		local @ARGV = split;
1483fb98d4aSespie		GetOptions %opt_def;
1493fb98d4aSespie	    }
1503fb98d4aSespie
1513fb98d4aSespie	    next;
1523fb98d4aSespie	}
1533fb98d4aSespie
1543fb98d4aSespie	$hash->{$key} ||= '';
1553fb98d4aSespie	$hash->{$key} .= $_;
1561cc83814Sespie    }
1571cc83814Sespie
1581cc83814Sespie    close INC;
1591cc83814Sespie
1603fb98d4aSespie    die "$this_program: no valid information found in `$inc'\n"
1613fb98d4aSespie	unless $key;
1623fb98d4aSespie}
1631cc83814Sespie
1641cc83814Sespie# Compress trailing blank lines.
1653fb98d4aSespiefor my $hash (\(%include, %append))
1661cc83814Sespie{
1673fb98d4aSespie    for (keys %$hash) { $hash->{$_} =~ s/\n+$/\n/ }
1681cc83814Sespie}
1691cc83814Sespie
170*c0141d96Sderaadt# Turn off localisation of executable's output.
1711cc83814Sespie@ENV{qw(LANGUAGE LANG LC_ALL)} = ('C') x 3;
1721cc83814Sespie
1733fb98d4aSespie# Turn off localisation of date (for strftime).
1741cc83814Sespiesetlocale LC_TIME, 'C';
1751cc83814Sespie
1763fb98d4aSespie# Grab help and version info from executable.
1773fb98d4aSespiemy ($help_text, $version_text) = map {
1783fb98d4aSespie    join '', map { s/ +$//; expand $_ } `$ARGV[0] --$_ 2>/dev/null`
1793fb98d4aSespie	or die "$this_program: can't get `--$_' info from $ARGV[0]\n"
1803fb98d4aSespie} qw(help version);
1811cc83814Sespie
1821cc83814Sespiemy $date = strftime "%B %Y", localtime;
1831cc83814Sespie(my $program = $ARGV[0]) =~ s!.*/!!;
1841cc83814Sespiemy $package = $program;
1851cc83814Sespiemy $version;
1861cc83814Sespie
1871cc83814Sespieif ($opt_output)
1881cc83814Sespie{
1891cc83814Sespie    unlink $opt_output
1901cc83814Sespie	or die "$this_program: can't unlink $opt_output ($!)\n"
1911cc83814Sespie	if -e $opt_output;
1921cc83814Sespie
1931cc83814Sespie    open STDOUT, ">$opt_output"
1941cc83814Sespie	or die "$this_program: can't create $opt_output ($!)\n";
1951cc83814Sespie}
1961cc83814Sespie
1971cc83814Sespie# The first line of the --version information is assumed to be in one
1981cc83814Sespie# of the following formats:
1991cc83814Sespie#
2001cc83814Sespie#   <version>
2011cc83814Sespie#   <program> <version>
2021cc83814Sespie#   {GNU,Free} <program> <version>
2031cc83814Sespie#   <program> ({GNU,Free} <package>) <version>
2041cc83814Sespie#   <program> - {GNU,Free} <package> <version>
2051cc83814Sespie#
2061cc83814Sespie# and seperated from any copyright/author details by a blank line.
2071cc83814Sespie
2083fb98d4aSespie($_, $version_text) = split /\n+/, $version_text, 2;
2091cc83814Sespie
2101cc83814Sespieif (/^(\S+) +\(((?:GNU|Free) +[^)]+)\) +(.*)/ or
2111cc83814Sespie    /^(\S+) +- *((?:GNU|Free) +\S+) +(.*)/)
2121cc83814Sespie{
2131cc83814Sespie    $program = $1;
2141cc83814Sespie    $package = $2;
2151cc83814Sespie    $version = $3;
2161cc83814Sespie}
2171cc83814Sespieelsif (/^((?:GNU|Free) +)?(\S+) +(.*)/)
2181cc83814Sespie{
2191cc83814Sespie    $program = $2;
2201cc83814Sespie    $package = $1 ? "$1$2" : $2;
2211cc83814Sespie    $version = $3;
2221cc83814Sespie}
2231cc83814Sespieelse
2241cc83814Sespie{
2251cc83814Sespie    $version = $_;
2261cc83814Sespie}
2271cc83814Sespie
2281cc83814Sespie$program =~ s!.*/!!;
2291cc83814Sespie
2303fb98d4aSespie# No info for `info' itself.
2311cc83814Sespie$opt_no_info = 1 if $program eq 'info';
2321cc83814Sespie
2333fb98d4aSespie# --name overrides --include contents.
2343fb98d4aSespie$include{NAME} = "$program \\- $opt_name\n" if $opt_name;
2351cc83814Sespie
2363fb98d4aSespie# Default (useless) NAME paragraph.
2373fb98d4aSespie$include{NAME} ||= "$program \\- manual page for $program $version\n";
2381cc83814Sespie
2391cc83814Sespie# Man pages traditionally have the page title in caps.
2401cc83814Sespiemy $PROGRAM = uc $program;
2411cc83814Sespie
2423fb98d4aSespie# Extract usage clause(s) [if any] for SYNOPSIS.
2433fb98d4aSespieif ($help_text =~ s/^Usage:( +(\S+))(.*)((?:\n(?: {6}\1| *or: +\S).*)*)//m)
2443fb98d4aSespie{
2453fb98d4aSespie    my @syn = $2 . $3;
2461cc83814Sespie
2473fb98d4aSespie    if ($_ = $4)
2483fb98d4aSespie    {
2493fb98d4aSespie	s/^\n//;
2503fb98d4aSespie	for (split /\n/) { s/^ *(or: +)?//; push @syn, $_ }
2513fb98d4aSespie    }
2523fb98d4aSespie
2533fb98d4aSespie    my $synopsis = '';
2543fb98d4aSespie    for (@syn)
2553fb98d4aSespie    {
2563fb98d4aSespie	$synopsis .= ".br\n" if $synopsis;
2573fb98d4aSespie	s!^\S*/!!;
2583fb98d4aSespie	s/^(\S+) *//;
2593fb98d4aSespie	$synopsis .= ".B $1\n";
2603fb98d4aSespie	s/\s+$//;
2613fb98d4aSespie	s/(([][]|\.\.+)+)/\\fR$1\\fI/g;
2623fb98d4aSespie	s/^/\\fI/ unless s/^\\fR//;
2633fb98d4aSespie	$_ .= '\fR';
2643fb98d4aSespie	s/(\\fI)( *)/$2$1/g;
2653fb98d4aSespie	s/\\fI\\fR//g;
2663fb98d4aSespie	s/^\\fR//;
2673fb98d4aSespie	s/\\fI$//;
2683fb98d4aSespie	s/^\./\\&./;
2693fb98d4aSespie
2703fb98d4aSespie	$synopsis .= "$_\n";
2713fb98d4aSespie    }
2723fb98d4aSespie
2733fb98d4aSespie    $include{SYNOPSIS} ||= $synopsis;
2743fb98d4aSespie}
2753fb98d4aSespie
2763fb98d4aSespie# Process text, initial section is DESCRIPTION.
2773fb98d4aSespiemy $sect = 'DESCRIPTION';
2783fb98d4aSespie$_ = "$help_text\n\n$version_text";
2793fb98d4aSespie
2803fb98d4aSespie# Normalise paragraph breaks.
2813fb98d4aSespies/^\n+//;
2823fb98d4aSespies/\n*$/\n/;
2833fb98d4aSespies/\n\n+/\n\n/g;
2843fb98d4aSespie
2853fb98d4aSespie# Temporarily exchange leading dots, apostrophes and backslashes for
2863fb98d4aSespie# tokens.
2873fb98d4aSespies/^\./\x80/mg;
2883fb98d4aSespies/^'/\x81/mg;
2893fb98d4aSespies/\\/\x82/g;
2903fb98d4aSespie
2913fb98d4aSespie# Start a new paragraph (if required) for these.
2923fb98d4aSespies/([^\n])\n(Report +bugs|Email +bug +reports +to|Written +by)/$1\n\n$2/g;
2931cc83814Sespie
2941cc83814Sespiesub convert_option;
2951cc83814Sespie
2963fb98d4aSespiewhile (length)
2971cc83814Sespie{
2983fb98d4aSespie    # Convert some standard paragraph names.
2993fb98d4aSespie    if (s/^(Options|Examples): *\n//)
3001cc83814Sespie    {
3013fb98d4aSespie	$sect = uc $1;
3021cc83814Sespie	next;
3031cc83814Sespie    }
3041cc83814Sespie
3053fb98d4aSespie    # Copyright section
3063fb98d4aSespie    if (/^Copyright +[(\xa9]/)
3071cc83814Sespie    {
3083fb98d4aSespie	$sect = 'COPYRIGHT';
3093fb98d4aSespie	$include{$sect} ||= '';
3103fb98d4aSespie	$include{$sect} .= ".PP\n" if $include{$sect};
3113fb98d4aSespie
3123fb98d4aSespie	my $copy;
3133fb98d4aSespie	($copy, $_) = split /\n\n/, $_, 2;
3143fb98d4aSespie
3153fb98d4aSespie	for ($copy)
3163fb98d4aSespie	{
3173fb98d4aSespie	    # Add back newline
3183fb98d4aSespie	    s/\n*$/\n/;
3193fb98d4aSespie
3203fb98d4aSespie	    # Convert iso9959-1 copyright symbol or (c) to nroff
3213fb98d4aSespie	    # character.
3223fb98d4aSespie	    s/^Copyright +(?:\xa9|\([Cc]\))/Copyright \\(co/mg;
3233fb98d4aSespie
3243fb98d4aSespie	    # Insert line breaks before additional copyright messages
3253fb98d4aSespie	    # and the disclaimer.
3263fb98d4aSespie	    s/(.)\n(Copyright |This +is +free +software)/$1\n.br\n$2/g;
3273fb98d4aSespie
3283fb98d4aSespie	    # Join hyphenated lines.
3293fb98d4aSespie	    s/([A-Za-z])-\n */$1/g;
3303fb98d4aSespie	}
3313fb98d4aSespie
3323fb98d4aSespie	$include{$sect} .= $copy;
3333fb98d4aSespie	$_ ||= '';
3343fb98d4aSespie	next;
3351cc83814Sespie    }
3361cc83814Sespie
3371cc83814Sespie    # Catch bug report text.
3383fb98d4aSespie    if (/^(Report +bugs|Email +bug +reports +to) /)
3391cc83814Sespie    {
3403fb98d4aSespie	$sect = 'REPORTING BUGS';
3413fb98d4aSespie    }
3423fb98d4aSespie
3433fb98d4aSespie    # Author section.
3443fb98d4aSespie    elsif (/^Written +by/)
3453fb98d4aSespie    {
3463fb98d4aSespie	$sect = 'AUTHOR';
3473fb98d4aSespie    }
3483fb98d4aSespie
3493fb98d4aSespie    # Examples, indicated by an indented leading $, % or > are
3503fb98d4aSespie    # rendered in a constant width font.
3513fb98d4aSespie    if (/^( +)([\$\%>] )\S/)
3523fb98d4aSespie    {
3533fb98d4aSespie	my $indent = $1;
3543fb98d4aSespie	my $prefix = $2;
3553fb98d4aSespie	my $break = '.IP';
3563fb98d4aSespie	$include{$sect} ||= '';
3573fb98d4aSespie	while (s/^$indent\Q$prefix\E(\S.*)\n*//)
3583fb98d4aSespie	{
3593fb98d4aSespie	    $include{$sect} .= "$break\n\\f(CW$prefix$1\\fR\n";
3603fb98d4aSespie	    $break = '.br';
3613fb98d4aSespie	}
3623fb98d4aSespie
3631cc83814Sespie	next;
3641cc83814Sespie    }
3651cc83814Sespie
3663fb98d4aSespie    my $matched = '';
3673fb98d4aSespie    $include{$sect} ||= '';
3683fb98d4aSespie
3693fb98d4aSespie    # Sub-sections have a trailing colon and the second line indented.
3703fb98d4aSespie    if (s/^(\S.*:) *\n / /)
3711cc83814Sespie    {
3723fb98d4aSespie	$matched .= $& if %append;
3733fb98d4aSespie	$include{$sect} .= qq(.SS "$1"\n);
3741cc83814Sespie    }
3751cc83814Sespie
3761cc83814Sespie    my $indent = 0;
3773fb98d4aSespie    my $content = '';
3781cc83814Sespie
3793fb98d4aSespie    # Option with description.
3803fb98d4aSespie    if (s/^( {1,10}([+-]\S.*?))(?:(  +)|\n( {20,}))(\S.*)\n//)
3811cc83814Sespie    {
3823fb98d4aSespie	$matched .= $& if %append;
3833fb98d4aSespie	$indent = length ($4 || "$1$3");
3843fb98d4aSespie	$content = ".TP\n\x83$2\n\x83$5\n";
3853fb98d4aSespie	unless ($4)
3863fb98d4aSespie	{
3873fb98d4aSespie	    # Indent may be different on second line.
3883fb98d4aSespie	    $indent = length $& if /^ {20,}/;
3893fb98d4aSespie	}
3901cc83814Sespie    }
3911cc83814Sespie
3923fb98d4aSespie    # Option without description.
3933fb98d4aSespie    elsif (s/^ {1,10}([+-]\S.*)\n//)
3941cc83814Sespie    {
3953fb98d4aSespie	$matched .= $& if %append;
3963fb98d4aSespie	$content = ".HP\n\x83$1\n";
3973fb98d4aSespie	$indent = 80; # not continued
3981cc83814Sespie    }
3991cc83814Sespie
4003fb98d4aSespie    # Indented paragraph with tag.
4013fb98d4aSespie    elsif (s/^( +(\S.*?)  +)(\S.*)\n//)
4023fb98d4aSespie    {
4033fb98d4aSespie	$matched .= $& if %append;
4043fb98d4aSespie	$indent = length $1;
4053fb98d4aSespie	$content = ".TP\n\x83$2\n\x83$3\n";
4063fb98d4aSespie    }
4073fb98d4aSespie
4083fb98d4aSespie    # Indented paragraph.
4093fb98d4aSespie    elsif (s/^( +)(\S.*)\n//)
4103fb98d4aSespie    {
4113fb98d4aSespie	$matched .= $& if %append;
4123fb98d4aSespie	$indent = length $1;
4133fb98d4aSespie	$content = ".IP\n\x83$2\n";
4143fb98d4aSespie    }
4153fb98d4aSespie
4163fb98d4aSespie    # Left justified paragraph.
4171cc83814Sespie    else
4181cc83814Sespie    {
4193fb98d4aSespie	s/(.*)\n//;
4203fb98d4aSespie	$matched .= $& if %append;
4213fb98d4aSespie	$content = ".PP\n" if $include{$sect};
4223fb98d4aSespie	$content .= "$1\n";
4231cc83814Sespie    }
4241cc83814Sespie
4253fb98d4aSespie    # Append continuations.
4263fb98d4aSespie    while (s/^ {$indent}(\S.*)\n//)
4273fb98d4aSespie    {
4283fb98d4aSespie	$matched .= $& if %append;
4293fb98d4aSespie	$content .= "\x83$1\n"
4301cc83814Sespie    }
4311cc83814Sespie
4323fb98d4aSespie    # Move to next paragraph.
4333fb98d4aSespie    s/^\n+//;
4341cc83814Sespie
4353fb98d4aSespie    for ($content)
4363fb98d4aSespie    {
4373fb98d4aSespie	# Leading dot and apostrophe protection.
4383fb98d4aSespie	s/\x83\./\x80/g;
4393fb98d4aSespie	s/\x83'/\x81/g;
4403fb98d4aSespie	s/\x83//g;
4411cc83814Sespie
4421cc83814Sespie	# Convert options.
4431cc83814Sespie	s/(^| )(-[][\w=-]+)/$1 . convert_option $2/mge;
4441cc83814Sespie    }
4451cc83814Sespie
4463fb98d4aSespie    # Check if matched paragraph contains /pat/.
4473fb98d4aSespie    if (%append)
4481cc83814Sespie    {
4493fb98d4aSespie	for my $pat (keys %append)
4503fb98d4aSespie	{
4513fb98d4aSespie	    if ($matched =~ $pat)
4523fb98d4aSespie	    {
4533fb98d4aSespie		$content .= ".PP\n" unless $append{$pat} =~ /^\./;
4543fb98d4aSespie		$content .= $append{$pat};
4553fb98d4aSespie	    }
4563fb98d4aSespie	}
4573fb98d4aSespie    }
4583fb98d4aSespie
4593fb98d4aSespie    $include{$sect} .= $content;
4601cc83814Sespie}
4611cc83814Sespie
4621cc83814Sespie# Refer to the real documentation.
4633fb98d4aSespieunless ($opt_no_info)
4641cc83814Sespie{
4653fb98d4aSespie    $sect = 'SEE ALSO';
4663fb98d4aSespie    $include{$sect} ||= '';
4673fb98d4aSespie    $include{$sect} .= ".PP\n" if $include{$sect};
4683fb98d4aSespie    $include{$sect} .= <<EOT;
4691cc83814SespieThe full documentation for
4701cc83814Sespie.B $program
4711cc83814Sespieis maintained as a Texinfo manual.  If the
4721cc83814Sespie.B info
4731cc83814Sespieand
4741cc83814Sespie.B $program
4751cc83814Sespieprograms are properly installed at your site, the command
4761cc83814Sespie.IP
4771cc83814Sespie.B info $program
4781cc83814Sespie.PP
4791cc83814Sespieshould give you access to the complete manual.
4801cc83814SespieEOT
4811cc83814Sespie}
4821cc83814Sespie
4833fb98d4aSespie# Output header.
4843fb98d4aSespieprint <<EOT;
4853fb98d4aSespie.\\" DO NOT MODIFY THIS FILE!  It was generated by $this_program $this_version.
4863fb98d4aSespie.TH $PROGRAM "$section" "$date" "$package $version" FSF
4873fb98d4aSespieEOT
4883fb98d4aSespie
4893fb98d4aSespie# Section ordering.
4903fb98d4aSespiemy @pre = qw(NAME SYNOPSIS DESCRIPTION OPTIONS EXAMPLES);
4913fb98d4aSespiemy @post = ('AUTHOR', 'REPORTING BUGS', 'COPYRIGHT', 'SEE ALSO');
4923fb98d4aSespiemy $filter = join '|', @pre, @post;
4933fb98d4aSespie
4943fb98d4aSespie# Output content.
4953fb98d4aSespiefor (@pre, (grep ! /^($filter)$/o, @include), @post)
4961cc83814Sespie{
4973fb98d4aSespie    if ($include{$_})
4983fb98d4aSespie    {
4993fb98d4aSespie	my $quote = /\W/ ? '"' : '';
5003fb98d4aSespie	print ".SH $quote$_$quote\n";
5011cc83814Sespie
5023fb98d4aSespie	for ($include{$_})
5033fb98d4aSespie	{
5043fb98d4aSespie	    # Replace leading dot, apostrophe and backslash tokens.
5053fb98d4aSespie	    s/\x80/\\&./g;
5063fb98d4aSespie	    s/\x81/\\&'/g;
5073fb98d4aSespie	    s/\x82/\\e/g;
5083fb98d4aSespie	    print;
5093fb98d4aSespie	}
5103fb98d4aSespie    }
5111cc83814Sespie}
5121cc83814Sespie
5131cc83814Sespieexit;
5141cc83814Sespie
5151cc83814Sespie# Convert option dashes to \- to stop nroff from hyphenating 'em, and
5161cc83814Sespie# embolden.  Option arguments get italicised.
5171cc83814Sespiesub convert_option
5181cc83814Sespie{
5193fb98d4aSespie    local $_ = '\fB' . shift;
5201cc83814Sespie
5213fb98d4aSespie    s/-/\\-/g;
5223fb98d4aSespie    unless (s/\[=(.*)\]$/\\fR[=\\fI$1\\fR]/)
5231cc83814Sespie    {
5243fb98d4aSespie	s/=(.)/\\fR=\\fI$1/;
5253fb98d4aSespie	s/ (.)/ \\fI$1/;
5263fb98d4aSespie	$_ .= '\fR';
5271cc83814Sespie    }
5281cc83814Sespie
5293fb98d4aSespie    $_;
5301cc83814Sespie}
531