3
# Generate a short man page from --help and --version output.
4
# Copyright ďż˝ 1997, 1998, 1999, 2000 Free Software Foundation, Inc.
6
# This program is free software; you can redistribute it and/or modify
7
# it under the terms of the GNU General Public License as published by
8
# the Free Software Foundation; either version 2, or (at your option)
11
# This program is distributed in the hope that it will be useful,
12
# but WITHOUT ANY WARRANTY; without even the implied warranty of
13
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14
# GNU General Public License for more details.
16
# You should have received a copy of the GNU General Public License
17
# along with this program; if not, write to the Free Software Foundation,
18
# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
20
# Written by Brendan O'Dea <bod@compusol.com.au>
21
# Available from ftp://ftp.gnu.org/gnu/help2man/
26
use Text::Tabs qw(expand);
27
use POSIX qw(strftime setlocale LC_TIME);
29
my $this_program = 'help2man';
30
my $this_version = '1.23';
31
my $version_info = <<EOT;
32
GNU $this_program $this_version
34
Copyright (C) 1997, 1998, 1999, 2000 Free Software Foundation, Inc.
35
This is free software; see the source for copying conditions. There is NO
36
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
38
Written by Brendan O'Dea <bod\@compusol.com.au>
41
my $help_info = <<EOT;
42
`$this_program' generates a man page out of `--help' and `--version' output.
44
Usage: $this_program [OPTION]... EXECUTABLE
46
-n, --name=STRING use `STRING' as the description for the NAME paragraph
47
-s, --section=SECTION use `SECTION' as the section for the man page
48
-i, --include=FILE include material from `FILE'
49
-I, --opt-include=FILE include material from `FILE' if it exists
50
-o, --output=FILE send output to `FILE'
51
-N, --no-info suppress pointer to Texinfo manual
52
--help print this help, then exit
53
--version print version number, then exit
55
EXECUTABLE should accept `--help' and `--version' options.
57
Report bugs to <bug-help2man\@gnu.org>.
61
my ($opt_name, @opt_include, $opt_output, $opt_no_info);
64
Getopt::Long::config('bundling');
66
'n|name=s' => \$opt_name,
67
's|section=s' => \$section,
68
'i|include=s' => sub { push @opt_include, [ pop, 1 ] },
69
'I|opt-include=s' => sub { push @opt_include, [ pop, 0 ] },
70
'o|output=s' => \$opt_output,
71
'N|no-info' => \$opt_no_info,
72
help => sub { print $help_info; exit },
73
version => sub { print $version_info; exit },
76
die $help_info unless @ARGV == 1;
80
my @include = (); # retain order given in include file
82
# Provide replacement `quote-regex' operator for pre-5.005.
83
BEGIN { eval q(sub qr { '' =~ $_[0]; $_[0] }) if $] < 5.005 }
85
# Process include file (if given). Format is:
98
my ($inc, $required) = @$_;
100
next unless -f $inc or $required;
101
die "$this_program: can't open `$inc' ($!)\n"
102
unless open INC, $inc;
105
my $hash = \%include;
116
push @include, $key unless $include{$key};
121
if (m!^/(.*)/([ims]*)!)
123
my $pat = $2 ? "(?$2)$1" : $1;
126
eval { $key = qr($pat) };
129
$@ =~ s/ at .*? line \d.*//;
137
# Silently ignore anything before the first
138
# section--allows for comments and revision info.
141
$hash->{$key} ||= '';
147
die "$this_program: no valid information found in `$inc'\n"
151
# Compress trailing blank lines.
152
for my $hash (\(%include, %append))
154
for (keys %$hash) { $hash->{$_} =~ s/\n+$/\n/ }
157
# Turn off localisation of executable's ouput.
158
@ENV{qw(LANGUAGE LANG LC_ALL)} = ('C') x 3;
160
# Turn off localisation of date (for strftime).
161
setlocale LC_TIME, 'C';
163
# Grab help and version info from executable.
164
my ($help_text, $version_text) = map {
165
join '', map { s/ +$//; expand $_ } `$ARGV[0] --$_ 2>/dev/null`
166
or die "$this_program: can't get `--$_' info from $ARGV[0]\n"
169
my $date = strftime "%B %Y", localtime;
170
(my $program = $ARGV[0]) =~ s!.*/!!;
171
my $package = $program;
177
or die "$this_program: can't unlink $opt_output ($!)\n"
180
open STDOUT, ">$opt_output"
181
or die "$this_program: can't create $opt_output ($!)\n";
184
# The first line of the --version information is assumed to be in one
185
# of the following formats:
188
# <program> <version>
189
# {GNU,Free} <program> <version>
190
# <program> ({GNU,Free} <package>) <version>
191
# <program> - {GNU,Free} <package> <version>
193
# and seperated from any copyright/author details by a blank line.
195
($_, $version_text) = split /\n+/, $version_text, 2;
197
if (/^(\S+) +\(((?:GNU|Free) +[^)]+)\) +(.*)/ or
198
/^(\S+) +- *((?:GNU|Free) +\S+) +(.*)/)
204
elsif (/^((?:GNU|Free) +)?(\S+) +(.*)/)
207
$package = $1 ? "$1$2" : $2;
217
# No info for `info' itself.
218
$opt_no_info = 1 if $program eq 'info';
220
# --name overrides --include contents.
221
$include{NAME} = "$program \\- $opt_name\n" if $opt_name;
223
# Default (useless) NAME paragraph.
224
$include{NAME} ||= "$program \\- manual page for $program $version\n";
226
# Man pages traditionally have the page title in caps.
227
my $PROGRAM = uc $program;
229
# Extract usage clause(s) [if any] for SYNOPSIS.
230
if ($help_text =~ s/^Usage:( +(\S+))(.*)((?:\n(?: {6}\1| *or: +\S).*)*)//m)
237
for (split /\n/) { s/^ *(or: +)?//; push @syn, $_ }
243
$synopsis .= ".br\n" if $synopsis;
246
$synopsis .= ".B $1\n";
248
s/(([][]|\.\.+)+)/\\fR$1\\fI/g;
249
s/^/\\fI/ unless s/^\\fR//;
260
$include{SYNOPSIS} ||= $synopsis;
263
# Process text, initial section is DESCRIPTION.
264
my $sect = 'DESCRIPTION';
265
$_ = "$help_text\n\n$version_text";
267
# Normalise paragraph breaks.
272
# Temporarily exchange leading dots, apostrophes and backslashes for
278
# Start a new paragraph (if required) for these.
279
s/([^\n])\n(Report +bugs|Email +bug +reports +to|Written +by)/$1\n\n$2/g;
285
# Convert some standard paragraph names.
286
if (s/^(Options|Examples): *\n//)
293
if (/^Copyright +[(\xa9]/)
296
$include{$sect} ||= '';
297
$include{$sect} .= ".PP\n" if $include{$sect};
300
($copy, $_) = split /\n\n/, $_, 2;
307
# Convert iso9959-1 copyright symbol or (c) to nroff
309
s/^Copyright +(?:\xa9|\([Cc]\))/Copyright \\(co/mg;
311
# Insert line breaks before additional copyright messages
312
# and the disclaimer.
313
s/(.)\n(Copyright |This +is +free +software)/$1\n.br\n$2/g;
315
# Join hyphenated lines.
316
s/([A-Za-z])-\n */$1/g;
319
$include{$sect} .= $copy;
324
# Catch bug report text.
325
if (/^(Report +bugs|Email +bug +reports +to) /)
327
$sect = 'REPORTING BUGS';
331
elsif (/^Written +by/)
336
# Examples, indicated by an indented leading $, % or > are
337
# rendered in a constant width font.
338
if (/^( +)([\$\%>] )\S/)
343
$include{$sect} ||= '';
344
while (s/^$indent\Q$prefix\E(\S.*)\n*//)
346
$include{$sect} .= "$break\n\\f(CW$prefix$1\\fR\n";
354
$include{$sect} ||= '';
356
# Sub-sections have a trailing colon and the second line indented.
357
if (s/^(\S.*:) *\n / /)
359
$matched .= $& if %append;
360
$include{$sect} .= qq(.SS "$1"\n);
366
# Option with description.
367
if (s/^( {1,10}([+-]\S.*?))(?:( +)|\n( {20,}))(\S.*)\n//)
369
$matched .= $& if %append;
370
$indent = length ($4 || "$1$3");
371
$content = ".TP\n\x83$2\n\x83$5\n";
374
# Indent may be different on second line.
375
$indent = length $& if /^ {20,}/;
379
# Option without description.
380
elsif (s/^ {1,10}([+-]\S.*)\n//)
382
$matched .= $& if %append;
383
$content = ".HP\n\x83$1\n";
384
$indent = 80; # not continued
387
# Indented paragraph with tag.
388
elsif (s/^( +(\S.*?) +)(\S.*)\n//)
390
$matched .= $& if %append;
392
$content = ".TP\n\x83$2\n\x83$3\n";
395
# Indented paragraph.
396
elsif (s/^( +)(\S.*)\n//)
398
$matched .= $& if %append;
400
$content = ".IP\n\x83$2\n";
403
# Left justified paragraph.
407
$matched .= $& if %append;
408
$content = ".PP\n" if $include{$sect};
412
# Append continuations.
413
while (s/^ {$indent}(\S.*)\n//)
415
$matched .= $& if %append;
416
$content .= "\x83$1\n"
419
# Move to next paragraph.
424
# Leading dot and apostrophe protection.
430
s/(^| )(-[][\w=-]+)/$1 . convert_option $2/mge;
433
# Check if matched paragraph contains /pat/.
436
for my $pat (keys %append)
438
if ($matched =~ $pat)
440
$content .= ".PP\n" unless $append{$pat} =~ /^\./;
441
$content .= $append{$pat};
446
$include{$sect} .= $content;
449
# Refer to the real documentation.
450
unless ($opt_no_info)
453
$include{$sect} ||= '';
454
$include{$sect} .= ".PP\n" if $include{$sect};
455
$include{$sect} .= <<EOT;
456
The full documentation for
458
is maintained as a Texinfo manual. If the
462
programs are properly installed at your site, the command
466
should give you access to the complete manual.
472
.\\" DO NOT MODIFY THIS FILE! It was generated by $this_program $this_version.
473
.TH $PROGRAM "$section" "$date" "$package $version" FSF
477
my @pre = qw(NAME SYNOPSIS DESCRIPTION OPTIONS EXAMPLES);
478
my @post = ('AUTHOR', 'REPORTING BUGS', 'COPYRIGHT', 'SEE ALSO');
479
my $filter = join '|', @pre, @post;
482
for (@pre, (grep ! /^($filter)$/o, @include), @post)
486
my $quote = /\W/ ? '"' : '';
487
print ".SH $quote$_$quote\n";
491
# Replace leading dot, apostrophe and backslash tokens.
502
# Convert option dashes to \- to stop nroff from hyphenating 'em, and
503
# embolden. Option arguments get italicised.
506
local $_ = '\fB' . shift;
509
unless (s/\[=(.*)\]$/\\fR[=\\fI$1\\fR]/)