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.24';
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);
63 'n|name=s' => \
$opt_name,
64 's|section=s' => \
$section,
65 'i|include=s' => sub { push @opt_include, [ pop, 1 ] },
66 'I|opt-include=s' => sub { push @opt_include, [ pop, 0 ] },
67 'o|output=s' => \
$opt_output,
68 'N|no-info' => \
$opt_no_info,
72 Getopt
::Long
::config
('bundling');
74 help
=> sub { print $help_info; exit },
75 version
=> sub { print $version_info; exit },
78 die $help_info unless @ARGV == 1;
82 my @include = (); # retain order given in include file
84 # Provide replacement `quote-regex' operator for pre-5.005.
85 BEGIN { eval q
(sub qr
{ '' =~ $_[0]; $_[0] }) if $] < 5.005 }
87 # Process include file (if given). Format is:
100 my ($inc, $required) = @
{shift @opt_include};
102 next unless -f
$inc or $required;
103 die "$this_program: can't open `$inc' ($!)\n"
104 unless open INC
, $inc;
107 my $hash = \
%include;
118 push @include, $key unless $include{$key};
123 if (m!^/(.*)/([ims]*)!)
125 my $pat = $2 ?
"(?$2)$1" : $1;
128 eval { $key = qr
($pat) };
131 $@
=~ s/ at .*? line \d.*//;
139 # Check for options before the first section--anything else is
140 # silently ignored, allowing the first for comments and
154 $hash->{$key} ||= '';
160 die "$this_program: no valid information found in `$inc'\n"
164 # Compress trailing blank lines.
165 for my $hash (\
(%include, %append))
167 for (keys %$hash) { $hash->{$_} =~ s/\n+$/\n/ }
170 # Turn off localisation of executable's ouput.
171 @ENV{qw(LANGUAGE LANG LC_ALL)} = ('C') x
3;
173 # Turn off localisation of date (for strftime).
174 setlocale LC_TIME
, 'C';
176 # Grab help and version info from executable.
177 my ($help_text, $version_text) = map {
178 join '', map { s/ +$//; expand
$_ } `$ARGV[0] --$_ 2>/dev/null`
179 or die "$this_program: can't get `--$_' info from $ARGV[0]\n"
182 my $date = strftime
"%B %Y", localtime;
183 (my $program = $ARGV[0]) =~ s!.*/!!;
184 my $package = $program;
190 or die "$this_program: can't unlink $opt_output ($!)\n"
193 open STDOUT
, ">$opt_output"
194 or die "$this_program: can't create $opt_output ($!)\n";
197 # The first line of the --version information is assumed to be in one
198 # of the following formats:
201 # <program> <version>
202 # {GNU,Free} <program> <version>
203 # <program> ({GNU,Free} <package>) <version>
204 # <program> - {GNU,Free} <package> <version>
206 # and seperated from any copyright/author details by a blank line.
208 ($_, $version_text) = split /\n+/, $version_text, 2;
210 if (/^(\S+) +\(((?:GNU|Free) +[^)]+)\) +(.*)/ or
211 /^(\S+) +- *((?:GNU|Free) +\S+) +(.*)/)
217 elsif (/^((?:GNU|Free) +)?(\S+) +(.*)/)
220 $package = $1 ?
"$1$2" : $2;
230 # No info for `info' itself.
231 $opt_no_info = 1 if $program eq 'info';
233 # --name overrides --include contents.
234 $include{NAME
} = "$program \\- $opt_name\n" if $opt_name;
236 # Default (useless) NAME paragraph.
237 $include{NAME
} ||= "$program \\- manual page for $program $version\n";
239 # Man pages traditionally have the page title in caps.
240 my $PROGRAM = uc $program;
242 # Extract usage clause(s) [if any] for SYNOPSIS.
243 if ($help_text =~ s/^Usage:( +(\S+))(.*)((?:\n(?: {6}\1| *or: +\S).*)*)//m)
250 for (split /\n/) { s/^ *(or: +)?//; push @syn, $_ }
256 $synopsis .= ".br\n" if $synopsis;
259 $synopsis .= ".B $1\n";
261 s/(([][]|\.\.+)+)/\\fR$1\\fI/g;
262 s/^/\\fI/ unless s/^\\fR//;
273 $include{SYNOPSIS
} ||= $synopsis;
276 # Process text, initial section is DESCRIPTION.
277 my $sect = 'DESCRIPTION';
278 $_ = "$help_text\n\n$version_text";
280 # Normalise paragraph breaks.
285 # Temporarily exchange leading dots, apostrophes and backslashes for
291 # Start a new paragraph (if required) for these.
292 s/([^\n])\n(Report +bugs|Email +bug +reports +to|Written +by)/$1\n\n$2/g;
298 # Convert some standard paragraph names.
299 if (s/^(Options|Examples): *\n//)
306 if (/^Copyright +[(\xa9]/)
309 $include{$sect} ||= '';
310 $include{$sect} .= ".PP\n" if $include{$sect};
313 ($copy, $_) = split /\n\n/, $_, 2;
320 # Convert iso9959-1 copyright symbol or (c) to nroff
322 s/^Copyright +(?:\xa9|\([Cc]\))/Copyright \\(co/mg;
324 # Insert line breaks before additional copyright messages
325 # and the disclaimer.
326 s/(.)\n(Copyright |This +is +free +software)/$1\n.br\n$2/g;
328 # Join hyphenated lines.
329 s/([A-Za-z])-\n */$1/g;
332 $include{$sect} .= $copy;
337 # Catch bug report text.
338 if (/^(Report +bugs|Email +bug +reports +to) /)
340 $sect = 'REPORTING BUGS';
344 elsif (/^Written +by/)
349 # Examples, indicated by an indented leading $, % or > are
350 # rendered in a constant width font.
351 if (/^( +)([\$\%>] )\S/)
356 $include{$sect} ||= '';
357 while (s/^$indent\Q$prefix\E(\S.*)\n*//)
359 $include{$sect} .= "$break\n\\f(CW$prefix$1\\fR\n";
367 $include{$sect} ||= '';
369 # Sub-sections have a trailing colon and the second line indented.
370 if (s/^(\S.*:) *\n / /)
372 $matched .= $& if %append;
373 $include{$sect} .= qq(.SS
"$1"\n);
379 # Option with description.
380 if (s/^( {1,10}([+-]\S.*?))(?:( +)|\n( {20,}))(\S.*)\n//)
382 $matched .= $& if %append;
383 $indent = length ($4 || "$1$3");
384 $content = ".TP\n\x83$2\n\x83$5\n";
387 # Indent may be different on second line.
388 $indent = length $& if /^ {20,}/;
392 # Option without description.
393 elsif (s/^ {1,10}([+-]\S.*)\n//)
395 $matched .= $& if %append;
396 $content = ".HP\n\x83$1\n";
397 $indent = 80; # not continued
400 # Indented paragraph with tag.
401 elsif (s/^( +(\S.*?) +)(\S.*)\n//)
403 $matched .= $& if %append;
405 $content = ".TP\n\x83$2\n\x83$3\n";
408 # Indented paragraph.
409 elsif (s/^( +)(\S.*)\n//)
411 $matched .= $& if %append;
413 $content = ".IP\n\x83$2\n";
416 # Left justified paragraph.
420 $matched .= $& if %append;
421 $content = ".PP\n" if $include{$sect};
425 # Append continuations.
426 while (s/^ {$indent}(\S.*)\n//)
428 $matched .= $& if %append;
429 $content .= "\x83$1\n"
432 # Move to next paragraph.
437 # Leading dot and apostrophe protection.
443 s/(^| )(-[][\w=-]+)/$1 . convert_option $2/mge;
446 # Check if matched paragraph contains /pat/.
449 for my $pat (keys %append)
451 if ($matched =~ $pat)
453 $content .= ".PP\n" unless $append{$pat} =~ /^\./;
454 $content .= $append{$pat};
459 $include{$sect} .= $content;
462 # Refer to the real documentation.
463 unless ($opt_no_info)
466 $include{$sect} ||= '';
467 $include{$sect} .= ".PP\n" if $include{$sect};
468 $include{$sect} .= <<EOT;
469 The full documentation for
471 is maintained as a Texinfo manual. If the
475 programs are properly installed at your site, the command
479 should give you access to the complete manual.
485 .\\" DO NOT MODIFY THIS FILE! It was generated by $this_program $this_version.
486 .TH $PROGRAM "$section" "$date" "$package $version" FSF
490 my @pre = qw(NAME SYNOPSIS DESCRIPTION OPTIONS EXAMPLES);
491 my @post = ('AUTHOR', 'REPORTING BUGS', 'COPYRIGHT', 'SEE ALSO');
492 my $filter = join '|', @pre, @post;
495 for (@pre, (grep ! /^($filter)$/o, @include), @post)
499 my $quote = /\W/ ?
'"' : '';
500 print ".SH $quote$_$quote\n";
504 # Replace leading dot, apostrophe and backslash tokens.
515 # Convert option dashes to \- to stop nroff from hyphenating 'em, and
516 # embolden. Option arguments get italicised.
519 local $_ = '\fB' . shift;
522 unless (s/\[=(.*)\]$/\\fR[=\\fI$1\\fR]/)