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