xref: /titanic_51/usr/src/grub/grub-0.97/docs/help2man (revision 1b8adde7ba7d5e04395c141c5400dc2cffd7d809)
1*1b8adde7SWilliam Kucharski#!/usr/bin/perl -w
2*1b8adde7SWilliam Kucharski
3*1b8adde7SWilliam Kucharski# Generate a short man page from --help and --version output.
4*1b8adde7SWilliam Kucharski# Copyright � 1997, 1998, 1999, 2000 Free Software Foundation, Inc.
5*1b8adde7SWilliam Kucharski
6*1b8adde7SWilliam Kucharski# This program is free software; you can redistribute it and/or modify
7*1b8adde7SWilliam Kucharski# it under the terms of the GNU General Public License as published by
8*1b8adde7SWilliam Kucharski# the Free Software Foundation; either version 2, or (at your option)
9*1b8adde7SWilliam Kucharski# any later version.
10*1b8adde7SWilliam Kucharski
11*1b8adde7SWilliam Kucharski# This program is distributed in the hope that it will be useful,
12*1b8adde7SWilliam Kucharski# but WITHOUT ANY WARRANTY; without even the implied warranty of
13*1b8adde7SWilliam Kucharski# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14*1b8adde7SWilliam Kucharski# GNU General Public License for more details.
15*1b8adde7SWilliam Kucharski
16*1b8adde7SWilliam Kucharski# You should have received a copy of the GNU General Public License
17*1b8adde7SWilliam Kucharski# along with this program; if not, write to the Free Software Foundation,
18*1b8adde7SWilliam Kucharski# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
19*1b8adde7SWilliam Kucharski
20*1b8adde7SWilliam Kucharski# Written by Brendan O'Dea <bod@compusol.com.au>
21*1b8adde7SWilliam Kucharski# Available from ftp://ftp.gnu.org/gnu/help2man/
22*1b8adde7SWilliam Kucharski
23*1b8adde7SWilliam Kucharskiuse 5.004;
24*1b8adde7SWilliam Kucharskiuse strict;
25*1b8adde7SWilliam Kucharskiuse Getopt::Long;
26*1b8adde7SWilliam Kucharskiuse Text::Tabs qw(expand);
27*1b8adde7SWilliam Kucharskiuse POSIX qw(strftime setlocale LC_TIME);
28*1b8adde7SWilliam Kucharski
29*1b8adde7SWilliam Kucharskimy $this_program = 'help2man';
30*1b8adde7SWilliam Kucharskimy $this_version = '1.23';
31*1b8adde7SWilliam Kucharskimy $version_info = <<EOT;
32*1b8adde7SWilliam KucharskiGNU $this_program $this_version
33*1b8adde7SWilliam Kucharski
34*1b8adde7SWilliam KucharskiCopyright (C) 1997, 1998, 1999, 2000 Free Software Foundation, Inc.
35*1b8adde7SWilliam KucharskiThis is free software; see the source for copying conditions.  There is NO
36*1b8adde7SWilliam Kucharskiwarranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
37*1b8adde7SWilliam Kucharski
38*1b8adde7SWilliam KucharskiWritten by Brendan O'Dea <bod\@compusol.com.au>
39*1b8adde7SWilliam KucharskiEOT
40*1b8adde7SWilliam Kucharski
41*1b8adde7SWilliam Kucharskimy $help_info = <<EOT;
42*1b8adde7SWilliam Kucharski`$this_program' generates a man page out of `--help' and `--version' output.
43*1b8adde7SWilliam Kucharski
44*1b8adde7SWilliam KucharskiUsage: $this_program [OPTION]... EXECUTABLE
45*1b8adde7SWilliam Kucharski
46*1b8adde7SWilliam Kucharski -n, --name=STRING       use `STRING' as the description for the NAME paragraph
47*1b8adde7SWilliam Kucharski -s, --section=SECTION   use `SECTION' as the section for the man page
48*1b8adde7SWilliam Kucharski -i, --include=FILE      include material from `FILE'
49*1b8adde7SWilliam Kucharski -I, --opt-include=FILE  include material from `FILE' if it exists
50*1b8adde7SWilliam Kucharski -o, --output=FILE       send output to `FILE'
51*1b8adde7SWilliam Kucharski -N, --no-info           suppress pointer to Texinfo manual
52*1b8adde7SWilliam Kucharski     --help              print this help, then exit
53*1b8adde7SWilliam Kucharski     --version           print version number, then exit
54*1b8adde7SWilliam Kucharski
55*1b8adde7SWilliam KucharskiEXECUTABLE should accept `--help' and `--version' options.
56*1b8adde7SWilliam Kucharski
57*1b8adde7SWilliam KucharskiReport bugs to <bug-help2man\@gnu.org>.
58*1b8adde7SWilliam KucharskiEOT
59*1b8adde7SWilliam Kucharski
60*1b8adde7SWilliam Kucharskimy $section = 1;
61*1b8adde7SWilliam Kucharskimy ($opt_name, @opt_include, $opt_output, $opt_no_info);
62*1b8adde7SWilliam Kucharski
63*1b8adde7SWilliam Kucharski# Parse options.
64*1b8adde7SWilliam KucharskiGetopt::Long::config('bundling');
65*1b8adde7SWilliam KucharskiGetOptions (
66*1b8adde7SWilliam Kucharski    'n|name=s'		=> \$opt_name,
67*1b8adde7SWilliam Kucharski    's|section=s'	=> \$section,
68*1b8adde7SWilliam Kucharski    'i|include=s'	=> sub { push @opt_include, [ pop, 1 ] },
69*1b8adde7SWilliam Kucharski    'I|opt-include=s'	=> sub { push @opt_include, [ pop, 0 ] },
70*1b8adde7SWilliam Kucharski    'o|output=s'	=> \$opt_output,
71*1b8adde7SWilliam Kucharski    'N|no-info'		=> \$opt_no_info,
72*1b8adde7SWilliam Kucharski    help		=> sub { print $help_info; exit },
73*1b8adde7SWilliam Kucharski    version		=> sub { print $version_info; exit },
74*1b8adde7SWilliam Kucharski) or die $help_info;
75*1b8adde7SWilliam Kucharski
76*1b8adde7SWilliam Kucharskidie $help_info unless @ARGV == 1;
77*1b8adde7SWilliam Kucharski
78*1b8adde7SWilliam Kucharskimy %include = ();
79*1b8adde7SWilliam Kucharskimy %append = ();
80*1b8adde7SWilliam Kucharskimy @include = (); # retain order given in include file
81*1b8adde7SWilliam Kucharski
82*1b8adde7SWilliam Kucharski# Provide replacement `quote-regex' operator for pre-5.005.
83*1b8adde7SWilliam KucharskiBEGIN { eval q(sub qr { '' =~ $_[0]; $_[0] }) if $] < 5.005 }
84*1b8adde7SWilliam Kucharski
85*1b8adde7SWilliam Kucharski# Process include file (if given).  Format is:
86*1b8adde7SWilliam Kucharski#
87*1b8adde7SWilliam Kucharski#   [section name]
88*1b8adde7SWilliam Kucharski#   verbatim text
89*1b8adde7SWilliam Kucharski#
90*1b8adde7SWilliam Kucharski# or
91*1b8adde7SWilliam Kucharski#
92*1b8adde7SWilliam Kucharski#   /pattern/
93*1b8adde7SWilliam Kucharski#   verbatim text
94*1b8adde7SWilliam Kucharski#
95*1b8adde7SWilliam Kucharski
96*1b8adde7SWilliam Kucharskifor (@opt_include)
97*1b8adde7SWilliam Kucharski{
98*1b8adde7SWilliam Kucharski    my ($inc, $required) = @$_;
99*1b8adde7SWilliam Kucharski
100*1b8adde7SWilliam Kucharski    next unless -f $inc or $required;
101*1b8adde7SWilliam Kucharski    die "$this_program: can't open `$inc' ($!)\n"
102*1b8adde7SWilliam Kucharski	unless open INC, $inc;
103*1b8adde7SWilliam Kucharski
104*1b8adde7SWilliam Kucharski    my $key;
105*1b8adde7SWilliam Kucharski    my $hash = \%include;
106*1b8adde7SWilliam Kucharski
107*1b8adde7SWilliam Kucharski    while (<INC>)
108*1b8adde7SWilliam Kucharski    {
109*1b8adde7SWilliam Kucharski	# [section]
110*1b8adde7SWilliam Kucharski	if (/^\[([^]]+)\]/)
111*1b8adde7SWilliam Kucharski	{
112*1b8adde7SWilliam Kucharski	    $key = uc $1;
113*1b8adde7SWilliam Kucharski	    $key =~ s/^\s+//;
114*1b8adde7SWilliam Kucharski	    $key =~ s/\s+$//;
115*1b8adde7SWilliam Kucharski	    $hash = \%include;
116*1b8adde7SWilliam Kucharski	    push @include, $key unless $include{$key};
117*1b8adde7SWilliam Kucharski	    next;
118*1b8adde7SWilliam Kucharski	}
119*1b8adde7SWilliam Kucharski
120*1b8adde7SWilliam Kucharski	# /pattern/
121*1b8adde7SWilliam Kucharski	if (m!^/(.*)/([ims]*)!)
122*1b8adde7SWilliam Kucharski	{
123*1b8adde7SWilliam Kucharski	    my $pat = $2 ? "(?$2)$1" : $1;
124*1b8adde7SWilliam Kucharski
125*1b8adde7SWilliam Kucharski	    # Check pattern.
126*1b8adde7SWilliam Kucharski	    eval { $key = qr($pat) };
127*1b8adde7SWilliam Kucharski	    if ($@)
128*1b8adde7SWilliam Kucharski	    {
129*1b8adde7SWilliam Kucharski		$@ =~ s/ at .*? line \d.*//;
130*1b8adde7SWilliam Kucharski		die "$inc:$.:$@";
131*1b8adde7SWilliam Kucharski	    }
132*1b8adde7SWilliam Kucharski
133*1b8adde7SWilliam Kucharski	    $hash = \%append;
134*1b8adde7SWilliam Kucharski	    next;
135*1b8adde7SWilliam Kucharski	}
136*1b8adde7SWilliam Kucharski
137*1b8adde7SWilliam Kucharski	# Silently ignore anything before the first
138*1b8adde7SWilliam Kucharski	# section--allows for comments and revision info.
139*1b8adde7SWilliam Kucharski	next unless $key;
140*1b8adde7SWilliam Kucharski
141*1b8adde7SWilliam Kucharski	$hash->{$key} ||= '';
142*1b8adde7SWilliam Kucharski	$hash->{$key} .= $_;
143*1b8adde7SWilliam Kucharski    }
144*1b8adde7SWilliam Kucharski
145*1b8adde7SWilliam Kucharski    close INC;
146*1b8adde7SWilliam Kucharski
147*1b8adde7SWilliam Kucharski    die "$this_program: no valid information found in `$inc'\n"
148*1b8adde7SWilliam Kucharski	unless $key;
149*1b8adde7SWilliam Kucharski}
150*1b8adde7SWilliam Kucharski
151*1b8adde7SWilliam Kucharski# Compress trailing blank lines.
152*1b8adde7SWilliam Kucharskifor my $hash (\(%include, %append))
153*1b8adde7SWilliam Kucharski{
154*1b8adde7SWilliam Kucharski    for (keys %$hash) { $hash->{$_} =~ s/\n+$/\n/ }
155*1b8adde7SWilliam Kucharski}
156*1b8adde7SWilliam Kucharski
157*1b8adde7SWilliam Kucharski# Turn off localisation of executable's ouput.
158*1b8adde7SWilliam Kucharski@ENV{qw(LANGUAGE LANG LC_ALL)} = ('C') x 3;
159*1b8adde7SWilliam Kucharski
160*1b8adde7SWilliam Kucharski# Turn off localisation of date (for strftime).
161*1b8adde7SWilliam Kucharskisetlocale LC_TIME, 'C';
162*1b8adde7SWilliam Kucharski
163*1b8adde7SWilliam Kucharski# Grab help and version info from executable.
164*1b8adde7SWilliam Kucharskimy ($help_text, $version_text) = map {
165*1b8adde7SWilliam Kucharski    join '', map { s/ +$//; expand $_ } `$ARGV[0] --$_ 2>/dev/null`
166*1b8adde7SWilliam Kucharski	or die "$this_program: can't get `--$_' info from $ARGV[0]\n"
167*1b8adde7SWilliam Kucharski} qw(help version);
168*1b8adde7SWilliam Kucharski
169*1b8adde7SWilliam Kucharskimy $date = strftime "%B %Y", localtime;
170*1b8adde7SWilliam Kucharski(my $program = $ARGV[0]) =~ s!.*/!!;
171*1b8adde7SWilliam Kucharskimy $package = $program;
172*1b8adde7SWilliam Kucharskimy $version;
173*1b8adde7SWilliam Kucharski
174*1b8adde7SWilliam Kucharskiif ($opt_output)
175*1b8adde7SWilliam Kucharski{
176*1b8adde7SWilliam Kucharski    unlink $opt_output
177*1b8adde7SWilliam Kucharski	or die "$this_program: can't unlink $opt_output ($!)\n"
178*1b8adde7SWilliam Kucharski	if -e $opt_output;
179*1b8adde7SWilliam Kucharski
180*1b8adde7SWilliam Kucharski    open STDOUT, ">$opt_output"
181*1b8adde7SWilliam Kucharski	or die "$this_program: can't create $opt_output ($!)\n";
182*1b8adde7SWilliam Kucharski}
183*1b8adde7SWilliam Kucharski
184*1b8adde7SWilliam Kucharski# The first line of the --version information is assumed to be in one
185*1b8adde7SWilliam Kucharski# of the following formats:
186*1b8adde7SWilliam Kucharski#
187*1b8adde7SWilliam Kucharski#   <version>
188*1b8adde7SWilliam Kucharski#   <program> <version>
189*1b8adde7SWilliam Kucharski#   {GNU,Free} <program> <version>
190*1b8adde7SWilliam Kucharski#   <program> ({GNU,Free} <package>) <version>
191*1b8adde7SWilliam Kucharski#   <program> - {GNU,Free} <package> <version>
192*1b8adde7SWilliam Kucharski#
193*1b8adde7SWilliam Kucharski# and seperated from any copyright/author details by a blank line.
194*1b8adde7SWilliam Kucharski
195*1b8adde7SWilliam Kucharski($_, $version_text) = split /\n+/, $version_text, 2;
196*1b8adde7SWilliam Kucharski
197*1b8adde7SWilliam Kucharskiif (/^(\S+) +\(((?:GNU|Free) +[^)]+)\) +(.*)/ or
198*1b8adde7SWilliam Kucharski    /^(\S+) +- *((?:GNU|Free) +\S+) +(.*)/)
199*1b8adde7SWilliam Kucharski{
200*1b8adde7SWilliam Kucharski    $program = $1;
201*1b8adde7SWilliam Kucharski    $package = $2;
202*1b8adde7SWilliam Kucharski    $version = $3;
203*1b8adde7SWilliam Kucharski}
204*1b8adde7SWilliam Kucharskielsif (/^((?:GNU|Free) +)?(\S+) +(.*)/)
205*1b8adde7SWilliam Kucharski{
206*1b8adde7SWilliam Kucharski    $program = $2;
207*1b8adde7SWilliam Kucharski    $package = $1 ? "$1$2" : $2;
208*1b8adde7SWilliam Kucharski    $version = $3;
209*1b8adde7SWilliam Kucharski}
210*1b8adde7SWilliam Kucharskielse
211*1b8adde7SWilliam Kucharski{
212*1b8adde7SWilliam Kucharski    $version = $_;
213*1b8adde7SWilliam Kucharski}
214*1b8adde7SWilliam Kucharski
215*1b8adde7SWilliam Kucharski$program =~ s!.*/!!;
216*1b8adde7SWilliam Kucharski
217*1b8adde7SWilliam Kucharski# No info for `info' itself.
218*1b8adde7SWilliam Kucharski$opt_no_info = 1 if $program eq 'info';
219*1b8adde7SWilliam Kucharski
220*1b8adde7SWilliam Kucharski# --name overrides --include contents.
221*1b8adde7SWilliam Kucharski$include{NAME} = "$program \\- $opt_name\n" if $opt_name;
222*1b8adde7SWilliam Kucharski
223*1b8adde7SWilliam Kucharski# Default (useless) NAME paragraph.
224*1b8adde7SWilliam Kucharski$include{NAME} ||= "$program \\- manual page for $program $version\n";
225*1b8adde7SWilliam Kucharski
226*1b8adde7SWilliam Kucharski# Man pages traditionally have the page title in caps.
227*1b8adde7SWilliam Kucharskimy $PROGRAM = uc $program;
228*1b8adde7SWilliam Kucharski
229*1b8adde7SWilliam Kucharski# Extract usage clause(s) [if any] for SYNOPSIS.
230*1b8adde7SWilliam Kucharskiif ($help_text =~ s/^Usage:( +(\S+))(.*)((?:\n(?: {6}\1| *or: +\S).*)*)//m)
231*1b8adde7SWilliam Kucharski{
232*1b8adde7SWilliam Kucharski    my @syn = $2 . $3;
233*1b8adde7SWilliam Kucharski
234*1b8adde7SWilliam Kucharski    if ($_ = $4)
235*1b8adde7SWilliam Kucharski    {
236*1b8adde7SWilliam Kucharski	s/^\n//;
237*1b8adde7SWilliam Kucharski	for (split /\n/) { s/^ *(or: +)?//; push @syn, $_ }
238*1b8adde7SWilliam Kucharski    }
239*1b8adde7SWilliam Kucharski
240*1b8adde7SWilliam Kucharski    my $synopsis = '';
241*1b8adde7SWilliam Kucharski    for (@syn)
242*1b8adde7SWilliam Kucharski    {
243*1b8adde7SWilliam Kucharski	$synopsis .= ".br\n" if $synopsis;
244*1b8adde7SWilliam Kucharski	s!^\S*/!!;
245*1b8adde7SWilliam Kucharski	s/^(\S+) *//;
246*1b8adde7SWilliam Kucharski	$synopsis .= ".B $1\n";
247*1b8adde7SWilliam Kucharski	s/\s+$//;
248*1b8adde7SWilliam Kucharski	s/(([][]|\.\.+)+)/\\fR$1\\fI/g;
249*1b8adde7SWilliam Kucharski	s/^/\\fI/ unless s/^\\fR//;
250*1b8adde7SWilliam Kucharski	$_ .= '\fR';
251*1b8adde7SWilliam Kucharski	s/(\\fI)( *)/$2$1/g;
252*1b8adde7SWilliam Kucharski	s/\\fI\\fR//g;
253*1b8adde7SWilliam Kucharski	s/^\\fR//;
254*1b8adde7SWilliam Kucharski	s/\\fI$//;
255*1b8adde7SWilliam Kucharski	s/^\./\\&./;
256*1b8adde7SWilliam Kucharski
257*1b8adde7SWilliam Kucharski	$synopsis .= "$_\n";
258*1b8adde7SWilliam Kucharski    }
259*1b8adde7SWilliam Kucharski
260*1b8adde7SWilliam Kucharski    $include{SYNOPSIS} ||= $synopsis;
261*1b8adde7SWilliam Kucharski}
262*1b8adde7SWilliam Kucharski
263*1b8adde7SWilliam Kucharski# Process text, initial section is DESCRIPTION.
264*1b8adde7SWilliam Kucharskimy $sect = 'DESCRIPTION';
265*1b8adde7SWilliam Kucharski$_ = "$help_text\n\n$version_text";
266*1b8adde7SWilliam Kucharski
267*1b8adde7SWilliam Kucharski# Normalise paragraph breaks.
268*1b8adde7SWilliam Kucharskis/^\n+//;
269*1b8adde7SWilliam Kucharskis/\n*$/\n/;
270*1b8adde7SWilliam Kucharskis/\n\n+/\n\n/g;
271*1b8adde7SWilliam Kucharski
272*1b8adde7SWilliam Kucharski# Temporarily exchange leading dots, apostrophes and backslashes for
273*1b8adde7SWilliam Kucharski# tokens.
274*1b8adde7SWilliam Kucharskis/^\./\x80/mg;
275*1b8adde7SWilliam Kucharskis/^'/\x81/mg;
276*1b8adde7SWilliam Kucharskis/\\/\x82/g;
277*1b8adde7SWilliam Kucharski
278*1b8adde7SWilliam Kucharski# Start a new paragraph (if required) for these.
279*1b8adde7SWilliam Kucharskis/([^\n])\n(Report +bugs|Email +bug +reports +to|Written +by)/$1\n\n$2/g;
280*1b8adde7SWilliam Kucharski
281*1b8adde7SWilliam Kucharskisub convert_option;
282*1b8adde7SWilliam Kucharski
283*1b8adde7SWilliam Kucharskiwhile (length)
284*1b8adde7SWilliam Kucharski{
285*1b8adde7SWilliam Kucharski    # Convert some standard paragraph names.
286*1b8adde7SWilliam Kucharski    if (s/^(Options|Examples): *\n//)
287*1b8adde7SWilliam Kucharski    {
288*1b8adde7SWilliam Kucharski	$sect = uc $1;
289*1b8adde7SWilliam Kucharski	next;
290*1b8adde7SWilliam Kucharski    }
291*1b8adde7SWilliam Kucharski
292*1b8adde7SWilliam Kucharski    # Copyright section
293*1b8adde7SWilliam Kucharski    if (/^Copyright +[(\xa9]/)
294*1b8adde7SWilliam Kucharski    {
295*1b8adde7SWilliam Kucharski	$sect = 'COPYRIGHT';
296*1b8adde7SWilliam Kucharski	$include{$sect} ||= '';
297*1b8adde7SWilliam Kucharski	$include{$sect} .= ".PP\n" if $include{$sect};
298*1b8adde7SWilliam Kucharski
299*1b8adde7SWilliam Kucharski	my $copy;
300*1b8adde7SWilliam Kucharski	($copy, $_) = split /\n\n/, $_, 2;
301*1b8adde7SWilliam Kucharski
302*1b8adde7SWilliam Kucharski	for ($copy)
303*1b8adde7SWilliam Kucharski	{
304*1b8adde7SWilliam Kucharski	    # Add back newline
305*1b8adde7SWilliam Kucharski	    s/\n*$/\n/;
306*1b8adde7SWilliam Kucharski
307*1b8adde7SWilliam Kucharski	    # Convert iso9959-1 copyright symbol or (c) to nroff
308*1b8adde7SWilliam Kucharski	    # character.
309*1b8adde7SWilliam Kucharski	    s/^Copyright +(?:\xa9|\([Cc]\))/Copyright \\(co/mg;
310*1b8adde7SWilliam Kucharski
311*1b8adde7SWilliam Kucharski	    # Insert line breaks before additional copyright messages
312*1b8adde7SWilliam Kucharski	    # and the disclaimer.
313*1b8adde7SWilliam Kucharski	    s/(.)\n(Copyright |This +is +free +software)/$1\n.br\n$2/g;
314*1b8adde7SWilliam Kucharski
315*1b8adde7SWilliam Kucharski	    # Join hyphenated lines.
316*1b8adde7SWilliam Kucharski	    s/([A-Za-z])-\n */$1/g;
317*1b8adde7SWilliam Kucharski	}
318*1b8adde7SWilliam Kucharski
319*1b8adde7SWilliam Kucharski	$include{$sect} .= $copy;
320*1b8adde7SWilliam Kucharski	$_ ||= '';
321*1b8adde7SWilliam Kucharski	next;
322*1b8adde7SWilliam Kucharski    }
323*1b8adde7SWilliam Kucharski
324*1b8adde7SWilliam Kucharski    # Catch bug report text.
325*1b8adde7SWilliam Kucharski    if (/^(Report +bugs|Email +bug +reports +to) /)
326*1b8adde7SWilliam Kucharski    {
327*1b8adde7SWilliam Kucharski	$sect = 'REPORTING BUGS';
328*1b8adde7SWilliam Kucharski    }
329*1b8adde7SWilliam Kucharski
330*1b8adde7SWilliam Kucharski    # Author section.
331*1b8adde7SWilliam Kucharski    elsif (/^Written +by/)
332*1b8adde7SWilliam Kucharski    {
333*1b8adde7SWilliam Kucharski	$sect = 'AUTHOR';
334*1b8adde7SWilliam Kucharski    }
335*1b8adde7SWilliam Kucharski
336*1b8adde7SWilliam Kucharski    # Examples, indicated by an indented leading $, % or > are
337*1b8adde7SWilliam Kucharski    # rendered in a constant width font.
338*1b8adde7SWilliam Kucharski    if (/^( +)([\$\%>] )\S/)
339*1b8adde7SWilliam Kucharski    {
340*1b8adde7SWilliam Kucharski	my $indent = $1;
341*1b8adde7SWilliam Kucharski	my $prefix = $2;
342*1b8adde7SWilliam Kucharski	my $break = '.IP';
343*1b8adde7SWilliam Kucharski	$include{$sect} ||= '';
344*1b8adde7SWilliam Kucharski	while (s/^$indent\Q$prefix\E(\S.*)\n*//)
345*1b8adde7SWilliam Kucharski	{
346*1b8adde7SWilliam Kucharski	    $include{$sect} .= "$break\n\\f(CW$prefix$1\\fR\n";
347*1b8adde7SWilliam Kucharski	    $break = '.br';
348*1b8adde7SWilliam Kucharski	}
349*1b8adde7SWilliam Kucharski
350*1b8adde7SWilliam Kucharski	next;
351*1b8adde7SWilliam Kucharski    }
352*1b8adde7SWilliam Kucharski
353*1b8adde7SWilliam Kucharski    my $matched = '';
354*1b8adde7SWilliam Kucharski    $include{$sect} ||= '';
355*1b8adde7SWilliam Kucharski
356*1b8adde7SWilliam Kucharski    # Sub-sections have a trailing colon and the second line indented.
357*1b8adde7SWilliam Kucharski    if (s/^(\S.*:) *\n / /)
358*1b8adde7SWilliam Kucharski    {
359*1b8adde7SWilliam Kucharski	$matched .= $& if %append;
360*1b8adde7SWilliam Kucharski	$include{$sect} .= qq(.SS "$1"\n);
361*1b8adde7SWilliam Kucharski    }
362*1b8adde7SWilliam Kucharski
363*1b8adde7SWilliam Kucharski    my $indent = 0;
364*1b8adde7SWilliam Kucharski    my $content = '';
365*1b8adde7SWilliam Kucharski
366*1b8adde7SWilliam Kucharski    # Option with description.
367*1b8adde7SWilliam Kucharski    if (s/^( {1,10}([+-]\S.*?))(?:(  +)|\n( {20,}))(\S.*)\n//)
368*1b8adde7SWilliam Kucharski    {
369*1b8adde7SWilliam Kucharski	$matched .= $& if %append;
370*1b8adde7SWilliam Kucharski	$indent = length ($4 || "$1$3");
371*1b8adde7SWilliam Kucharski	$content = ".TP\n\x83$2\n\x83$5\n";
372*1b8adde7SWilliam Kucharski	unless ($4)
373*1b8adde7SWilliam Kucharski	{
374*1b8adde7SWilliam Kucharski	    # Indent may be different on second line.
375*1b8adde7SWilliam Kucharski	    $indent = length $& if /^ {20,}/;
376*1b8adde7SWilliam Kucharski	}
377*1b8adde7SWilliam Kucharski    }
378*1b8adde7SWilliam Kucharski
379*1b8adde7SWilliam Kucharski    # Option without description.
380*1b8adde7SWilliam Kucharski    elsif (s/^ {1,10}([+-]\S.*)\n//)
381*1b8adde7SWilliam Kucharski    {
382*1b8adde7SWilliam Kucharski	$matched .= $& if %append;
383*1b8adde7SWilliam Kucharski	$content = ".HP\n\x83$1\n";
384*1b8adde7SWilliam Kucharski	$indent = 80; # not continued
385*1b8adde7SWilliam Kucharski    }
386*1b8adde7SWilliam Kucharski
387*1b8adde7SWilliam Kucharski    # Indented paragraph with tag.
388*1b8adde7SWilliam Kucharski    elsif (s/^( +(\S.*?)  +)(\S.*)\n//)
389*1b8adde7SWilliam Kucharski    {
390*1b8adde7SWilliam Kucharski	$matched .= $& if %append;
391*1b8adde7SWilliam Kucharski	$indent = length $1;
392*1b8adde7SWilliam Kucharski	$content = ".TP\n\x83$2\n\x83$3\n";
393*1b8adde7SWilliam Kucharski    }
394*1b8adde7SWilliam Kucharski
395*1b8adde7SWilliam Kucharski    # Indented paragraph.
396*1b8adde7SWilliam Kucharski    elsif (s/^( +)(\S.*)\n//)
397*1b8adde7SWilliam Kucharski    {
398*1b8adde7SWilliam Kucharski	$matched .= $& if %append;
399*1b8adde7SWilliam Kucharski	$indent = length $1;
400*1b8adde7SWilliam Kucharski	$content = ".IP\n\x83$2\n";
401*1b8adde7SWilliam Kucharski    }
402*1b8adde7SWilliam Kucharski
403*1b8adde7SWilliam Kucharski    # Left justified paragraph.
404*1b8adde7SWilliam Kucharski    else
405*1b8adde7SWilliam Kucharski    {
406*1b8adde7SWilliam Kucharski	s/(.*)\n//;
407*1b8adde7SWilliam Kucharski	$matched .= $& if %append;
408*1b8adde7SWilliam Kucharski	$content = ".PP\n" if $include{$sect};
409*1b8adde7SWilliam Kucharski	$content .= "$1\n";
410*1b8adde7SWilliam Kucharski    }
411*1b8adde7SWilliam Kucharski
412*1b8adde7SWilliam Kucharski    # Append continuations.
413*1b8adde7SWilliam Kucharski    while (s/^ {$indent}(\S.*)\n//)
414*1b8adde7SWilliam Kucharski    {
415*1b8adde7SWilliam Kucharski	$matched .= $& if %append;
416*1b8adde7SWilliam Kucharski	$content .= "\x83$1\n"
417*1b8adde7SWilliam Kucharski    }
418*1b8adde7SWilliam Kucharski
419*1b8adde7SWilliam Kucharski    # Move to next paragraph.
420*1b8adde7SWilliam Kucharski    s/^\n+//;
421*1b8adde7SWilliam Kucharski
422*1b8adde7SWilliam Kucharski    for ($content)
423*1b8adde7SWilliam Kucharski    {
424*1b8adde7SWilliam Kucharski	# Leading dot and apostrophe protection.
425*1b8adde7SWilliam Kucharski	s/\x83\./\x80/g;
426*1b8adde7SWilliam Kucharski	s/\x83'/\x81/g;
427*1b8adde7SWilliam Kucharski	s/\x83//g;
428*1b8adde7SWilliam Kucharski
429*1b8adde7SWilliam Kucharski	# Convert options.
430*1b8adde7SWilliam Kucharski	s/(^| )(-[][\w=-]+)/$1 . convert_option $2/mge;
431*1b8adde7SWilliam Kucharski    }
432*1b8adde7SWilliam Kucharski
433*1b8adde7SWilliam Kucharski    # Check if matched paragraph contains /pat/.
434*1b8adde7SWilliam Kucharski    if (%append)
435*1b8adde7SWilliam Kucharski    {
436*1b8adde7SWilliam Kucharski	for my $pat (keys %append)
437*1b8adde7SWilliam Kucharski	{
438*1b8adde7SWilliam Kucharski	    if ($matched =~ $pat)
439*1b8adde7SWilliam Kucharski	    {
440*1b8adde7SWilliam Kucharski		$content .= ".PP\n" unless $append{$pat} =~ /^\./;
441*1b8adde7SWilliam Kucharski		$content .= $append{$pat};
442*1b8adde7SWilliam Kucharski	    }
443*1b8adde7SWilliam Kucharski	}
444*1b8adde7SWilliam Kucharski    }
445*1b8adde7SWilliam Kucharski
446*1b8adde7SWilliam Kucharski    $include{$sect} .= $content;
447*1b8adde7SWilliam Kucharski}
448*1b8adde7SWilliam Kucharski
449*1b8adde7SWilliam Kucharski# Refer to the real documentation.
450*1b8adde7SWilliam Kucharskiunless ($opt_no_info)
451*1b8adde7SWilliam Kucharski{
452*1b8adde7SWilliam Kucharski    $sect = 'SEE ALSO';
453*1b8adde7SWilliam Kucharski    $include{$sect} ||= '';
454*1b8adde7SWilliam Kucharski    $include{$sect} .= ".PP\n" if $include{$sect};
455*1b8adde7SWilliam Kucharski    $include{$sect} .= <<EOT;
456*1b8adde7SWilliam KucharskiThe full documentation for
457*1b8adde7SWilliam Kucharski.B $program
458*1b8adde7SWilliam Kucharskiis maintained as a Texinfo manual.  If the
459*1b8adde7SWilliam Kucharski.B info
460*1b8adde7SWilliam Kucharskiand
461*1b8adde7SWilliam Kucharski.B $program
462*1b8adde7SWilliam Kucharskiprograms are properly installed at your site, the command
463*1b8adde7SWilliam Kucharski.IP
464*1b8adde7SWilliam Kucharski.B info $program
465*1b8adde7SWilliam Kucharski.PP
466*1b8adde7SWilliam Kucharskishould give you access to the complete manual.
467*1b8adde7SWilliam KucharskiEOT
468*1b8adde7SWilliam Kucharski}
469*1b8adde7SWilliam Kucharski
470*1b8adde7SWilliam Kucharski# Output header.
471*1b8adde7SWilliam Kucharskiprint <<EOT;
472*1b8adde7SWilliam Kucharski.\\" DO NOT MODIFY THIS FILE!  It was generated by $this_program $this_version.
473*1b8adde7SWilliam Kucharski.TH $PROGRAM "$section" "$date" "$package $version" FSF
474*1b8adde7SWilliam KucharskiEOT
475*1b8adde7SWilliam Kucharski
476*1b8adde7SWilliam Kucharski# Section ordering.
477*1b8adde7SWilliam Kucharskimy @pre = qw(NAME SYNOPSIS DESCRIPTION OPTIONS EXAMPLES);
478*1b8adde7SWilliam Kucharskimy @post = ('AUTHOR', 'REPORTING BUGS', 'COPYRIGHT', 'SEE ALSO');
479*1b8adde7SWilliam Kucharskimy $filter = join '|', @pre, @post;
480*1b8adde7SWilliam Kucharski
481*1b8adde7SWilliam Kucharski# Output content.
482*1b8adde7SWilliam Kucharskifor (@pre, (grep ! /^($filter)$/o, @include), @post)
483*1b8adde7SWilliam Kucharski{
484*1b8adde7SWilliam Kucharski    if ($include{$_})
485*1b8adde7SWilliam Kucharski    {
486*1b8adde7SWilliam Kucharski	my $quote = /\W/ ? '"' : '';
487*1b8adde7SWilliam Kucharski	print ".SH $quote$_$quote\n";
488*1b8adde7SWilliam Kucharski
489*1b8adde7SWilliam Kucharski	for ($include{$_})
490*1b8adde7SWilliam Kucharski	{
491*1b8adde7SWilliam Kucharski	    # Replace leading dot, apostrophe and backslash tokens.
492*1b8adde7SWilliam Kucharski	    s/\x80/\\&./g;
493*1b8adde7SWilliam Kucharski	    s/\x81/\\&'/g;
494*1b8adde7SWilliam Kucharski	    s/\x82/\\e/g;
495*1b8adde7SWilliam Kucharski	    print;
496*1b8adde7SWilliam Kucharski	}
497*1b8adde7SWilliam Kucharski    }
498*1b8adde7SWilliam Kucharski}
499*1b8adde7SWilliam Kucharski
500*1b8adde7SWilliam Kucharskiexit;
501*1b8adde7SWilliam Kucharski
502*1b8adde7SWilliam Kucharski# Convert option dashes to \- to stop nroff from hyphenating 'em, and
503*1b8adde7SWilliam Kucharski# embolden.  Option arguments get italicised.
504*1b8adde7SWilliam Kucharskisub convert_option
505*1b8adde7SWilliam Kucharski{
506*1b8adde7SWilliam Kucharski    local $_ = '\fB' . shift;
507*1b8adde7SWilliam Kucharski
508*1b8adde7SWilliam Kucharski    s/-/\\-/g;
509*1b8adde7SWilliam Kucharski    unless (s/\[=(.*)\]$/\\fR[=\\fI$1\\fR]/)
510*1b8adde7SWilliam Kucharski    {
511*1b8adde7SWilliam Kucharski	s/=(.)/\\fR=\\fI$1/;
512*1b8adde7SWilliam Kucharski	s/ (.)/ \\fI$1/;
513*1b8adde7SWilliam Kucharski	$_ .= '\fR';
514*1b8adde7SWilliam Kucharski    }
515*1b8adde7SWilliam Kucharski
516*1b8adde7SWilliam Kucharski    $_;
517*1b8adde7SWilliam Kucharski}
518