3 # Generate a short man page from --help and --version output.
4 # Copyright (C) 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004
5 # Free Software Foundation, Inc.
7 # This program is free software; you can redistribute it and/or modify
8 # it under the terms of the GNU General Public License as published by
9 # the Free Software Foundation; either version 2, or (at your option)
12 # This program is distributed in the hope that it will be useful,
13 # but WITHOUT ANY WARRANTY; without even the implied warranty of
14 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 # GNU General Public License for more details.
17 # You should have received a copy of the GNU General Public License
18 # along with this program; if not, write to the Free Software Foundation,
19 # Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
21 # Written by Brendan O'Dea <bod@debian.org>
22 # Available from ftp://ftp.gnu.org/gnu/help2man/
27 use Text
::Tabs
qw(expand);
28 use POSIX
qw(strftime setlocale LC_ALL);
31 my $this_program = 'help2man';
32 my $this_version = '1.35';
37 require Locale
::gettext
;
38 Locale
::gettext
->import;
42 unless ($have_gettext)
44 *gettext
= sub { $_[0] };
52 textdomain
$this_program;
54 my ($user_locale) = grep defined && length,
55 (map $ENV{$_}, qw(LANGUAGE LC_ALL LC_MESSAGES LANG)), 'C';
57 sub kark
# die with message formatted in the invoking user's locale
59 setlocale LC_ALL
, $user_locale;
60 my $fmt = gettext
shift;
61 die +(sprintf $fmt, @_), "\n";
65 my $version_info = sprintf _
(<<'EOT'), $this_program, $this_version;
68 Copyright (C) 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004 Free Software
70 This is free software; see the source for copying conditions. There is NO
71 warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
73 Written by Brendan O'Dea <bod@debian.org>
76 my $help_info = sprintf _
(<<'EOT'), $this_program, $this_program;
77 `%s' generates a man page out of `--help' and `--version' output.
79 Usage: %s [OPTION]... EXECUTABLE
81 -n, --name=STRING description for the NAME paragraph
82 -s, --section=SECTION section number for manual page (1, 6, 8)
83 -m, --manual=TEXT name of manual (User Commands, ...)
84 -S, --source=TEXT source of program (FSF, Debian, ...)
85 -L, --locale=STRING select locale (default "C")
86 -i, --include=FILE include material from `FILE'
87 -I, --opt-include=FILE include material from `FILE' if it exists
88 -o, --output=FILE send output to `FILE'
89 -p, --info-page=TEXT name of Texinfo manual
90 -N, --no-info suppress pointer to Texinfo manual
91 --help print this help, then exit
92 --version print version number, then exit
94 EXECUTABLE should accept `--help' and `--version' options although
95 alternatives may be specified using:
97 -h, --help-option=STRING help option string
98 -v, --version-option=STRING version option string
100 Report bugs to <bug-help2man@gnu.org>.
107 my $help_option = '--help';
108 my $version_option = '--version';
109 my ($opt_name, @opt_include, $opt_output, $opt_info, $opt_no_info);
112 'n|name=s' => \
$opt_name,
113 's|section=s' => \
$section,
114 'm|manual=s' => \
$manual,
115 'S|source=s' => \
$source,
116 'L|locale=s' => \
$locale,
117 'i|include=s' => sub { push @opt_include, [ pop, 1 ] },
118 'I|opt-include=s' => sub { push @opt_include, [ pop, 0 ] },
119 'o|output=s' => \
$opt_output,
120 'p|info-page=s' => \
$opt_info,
121 'N|no-info' => \
$opt_no_info,
122 'h|help-option=s' => \
$help_option,
123 'v|version-option=s' => \
$version_option,
127 Getopt
::Long
::config
('bundling');
128 GetOptions
(%opt_def,
129 help
=> sub { print $help_info; exit },
130 version
=> sub { print $version_info; exit },
133 die $help_info unless @ARGV == 1;
135 die "$this_program: no locale support (Locale::gettext required)\n"
136 unless $locale eq 'C' or $have_gettext;
138 # Set localisation of date and executable's ouput.
139 delete @ENV{qw(LANGUAGE LC_MESSAGES LANG)};
140 setlocale LC_ALL
, $ENV{LC_ALL
} = $locale;
144 my @include = (); # retain order given in include file
146 # Process include file (if given). Format is:
159 my ($inc, $required) = @
{shift @opt_include};
161 next unless -f
$inc or $required;
162 kark N_
("%s: can't open `%s' (%s)"), $this_program, $inc, $!
163 unless open INC
, $inc;
166 my $hash = \
%include;
177 push @include, $key unless $include{$key};
182 if (m!^/(.*)/([ims]*)!)
184 my $pat = $2 ?
"(?$2)$1" : $1;
187 eval { $key = qr
($pat) };
190 $@
=~ s/ at .*? line \d.*//;
198 # Check for options before the first section--anything else is
199 # silently ignored, allowing the first for comments and
213 $hash->{$key} ||= '';
219 kark N_
("%s: no valid information found in `%s'"), $this_program, $inc
223 # Compress trailing blank lines.
224 for my $hash (\
(%include, %append))
226 for (keys %$hash) { $hash->{$_} =~ s/\n+$/\n/ }
229 # Grab help and version info from executable.
230 my ($help_text, $version_text) = map {
231 join '', map { s/ +$//; expand
$_ } `$ARGV[0] $_ 2>/dev/null`
232 or kark N_
("%s: can't get `%s' info from %s"), $this_program,
234 } $help_option, $version_option;
236 my $date = strftime
"%B %Y", localtime;
237 (my $program = $ARGV[0]) =~ s!.*/!!;
238 my $package = $program;
243 unlink $opt_output or kark N_
("%s: can't unlink %s (%s)"),
244 $this_program, $opt_output, $! if -e
$opt_output;
246 open STDOUT
, ">$opt_output"
247 or kark N_
("%s: can't create %s (%s)"), $this_program, $opt_output, $!;
250 # The first line of the --version information is assumed to be in one
251 # of the following formats:
254 # <program> <version>
255 # {GNU,Free} <program> <version>
256 # <program> ({GNU,Free} <package>) <version>
257 # <program> - {GNU,Free} <package> <version>
259 # and seperated from any copyright/author details by a blank line.
261 ($_, $version_text) = split /\n+/, $version_text, 2;
263 if (/^(\S+) +\(((?:GNU|Free) +[^)]+)\) +(.*)/ or
264 /^(\S+) +- *((?:GNU|Free) +\S+) +(.*)/)
270 elsif (/^((?:GNU|Free) +)?(\S+) +(.*)/)
273 $package = $1 ?
"$1$2" : $2;
283 # No info for `info' itself.
284 $opt_no_info = 1 if $program eq 'info';
286 for ($include{_
('NAME')})
288 if ($opt_name) # --name overrides --include contents.
290 $_ = "$program \\- $opt_name\n";
292 elsif ($_) # Use first name given as $program
294 $program = $1 if /^([^\s,]+)(?:,?\s*[^\s,\\-]+)*\s+\\?-/;
296 else # Set a default (useless) NAME paragraph.
298 $_ = sprintf _
("%s \\- manual page for %s %s") . "\n", $program,
303 # Man pages traditionally have the page title in caps.
304 my $PROGRAM = uc $program;
306 # Set default page head/footers
307 $source ||= "$program $version";
312 if (/^(1[Mm]|8)/) { $manual = _
('System Administration Utilities') }
313 elsif (/^6/) { $manual = _
('Games') }
314 else { $manual = _
('User Commands') }
318 # Extract usage clause(s) [if any] for SYNOPSIS.
319 my $PAT_USAGE = _
('Usage');
320 my $PAT_USAGE_CONT = _
('or');
321 if ($help_text =~ s/^($PAT_USAGE):( +(\S+))(.*)((?:\n(?: {6}\1| *($PAT_USAGE_CONT): +\S).*)*)//om)
328 for (split /\n/) { s/^ *(($PAT_USAGE_CONT): +)?//o; push @syn, $_ }
334 $synopsis .= ".br\n" if $synopsis;
337 $synopsis .= ".B $1\n";
339 s/(([][]|\.\.+)+)/\\fR$1\\fI/g;
340 s/^/\\fI/ unless s/^\\fR//;
351 $include{_
('SYNOPSIS')} ||= $synopsis;
354 # Process text, initial section is DESCRIPTION.
355 my $sect = _
('DESCRIPTION');
356 $_ = "$help_text\n\n$version_text";
358 # Normalise paragraph breaks.
363 # Join hyphenated lines.
364 s/([A-Za-z])-\n *([A-Za-z])/$1$2/g;
366 # Temporarily exchange leading dots, apostrophes and backslashes for
372 my $PAT_BUGS = _
('Report +bugs|Email +bug +reports +to');
373 my $PAT_AUTHOR = _
('Written +by');
374 my $PAT_OPTIONS = _
('Options');
375 my $PAT_EXAMPLES = _
('Examples');
376 my $PAT_FREE_SOFTWARE = _
('This +is +free +software');
378 # Start a new paragraph (if required) for these.
379 s/([^\n])\n($PAT_BUGS|$PAT_AUTHOR)/$1\n\n$2/og;
385 # Convert some standard paragraph names.
386 if (s/^($PAT_OPTIONS): *\n//o)
388 $sect = _
('OPTIONS');
391 elsif (s/^($PAT_EXAMPLES): *\n//o)
393 $sect = _
('EXAMPLES');
398 if (/^Copyright +[(\xa9]/)
400 $sect = _
('COPYRIGHT');
401 $include{$sect} ||= '';
402 $include{$sect} .= ".PP\n" if $include{$sect};
405 ($copy, $_) = split /\n\n/, $_, 2;
412 # Convert iso9959-1 copyright symbol or (c) to nroff
414 s/^Copyright +(?:\xa9|\([Cc]\))/Copyright \\(co/mg;
416 # Insert line breaks before additional copyright messages
417 # and the disclaimer.
418 s/(.)\n(Copyright |$PAT_FREE_SOFTWARE)/$1\n.br\n$2/og;
421 $include{$sect} .= $copy;
426 # Catch bug report text.
427 if (/^($PAT_BUGS) /o)
429 $sect = _
('REPORTING BUGS');
433 elsif (/^($PAT_AUTHOR)/o)
438 # Examples, indicated by an indented leading $, % or > are
439 # rendered in a constant width font.
440 if (/^( +)([\$\%>] )\S/)
445 $include{$sect} ||= '';
446 while (s/^$indent\Q$prefix\E(\S.*)\n*//)
448 $include{$sect} .= "$break\n\\f(CW$prefix$1\\fR\n";
456 $include{$sect} ||= '';
458 # Sub-sections have a trailing colon and the second line indented.
459 if (s/^(\S.*:) *\n / /)
461 $matched .= $& if %append;
462 $include{$sect} .= qq(.SS
"$1"\n);
468 # Option with description.
469 if (s/^( {1,10}([+-]\S.*?))(?:( +(?!-))|\n( {20,}))(\S.*)\n//)
471 $matched .= $& if %append;
472 $indent = length ($4 || "$1$3");
473 $content = ".TP\n\x84$2\n\x84$5\n";
476 # Indent may be different on second line.
477 $indent = length $& if /^ {20,}/;
481 # Option without description.
482 elsif (s/^ {1,10}([+-]\S.*)\n//)
484 $matched .= $& if %append;
485 $content = ".HP\n\x84$1\n";
486 $indent = 80; # not continued
489 # Indented paragraph with tag.
490 elsif (s/^( +(\S.*?) +)(\S.*)\n//)
492 $matched .= $& if %append;
494 $content = ".TP\n\x84$2\n\x84$3\n";
497 # Indented paragraph.
498 elsif (s/^( +)(\S.*)\n//)
500 $matched .= $& if %append;
502 $content = ".IP\n\x84$2\n";
505 # Left justified paragraph.
509 $matched .= $& if %append;
510 $content = ".PP\n" if $include{$sect};
514 # Append continuations.
515 while ($indent ?
s/^ {$indent}(\S.*)\n// : s/^(\S.*)\n//)
517 $matched .= $& if %append;
518 $content .= "\x84$1\n"
521 # Move to next paragraph.
526 # Leading dot and apostrophe protection.
532 s/(^| |\()(-[][\w=-]+)/$1 . convert_option $2/mge;
534 # Escape remaining hyphens
538 # Check if matched paragraph contains /pat/.
541 for my $pat (keys %append)
543 if ($matched =~ $pat)
545 $content .= ".PP\n" unless $append{$pat} =~ /^\./;
546 $content .= $append{$pat};
551 $include{$sect} .= $content;
554 # Refer to the real documentation.
555 unless ($opt_no_info)
557 my $info_page = $opt_info || $program;
559 $sect = _
('SEE ALSO');
560 $include{$sect} ||= '';
561 $include{$sect} .= ".PP\n" if $include{$sect};
562 $include{$sect} .= sprintf _
(<<'EOT'), $program, $program, $info_page;
563 The full documentation for
565 is maintained as a Texinfo manual. If the
569 programs are properly installed at your site, the command
573 should give you access to the complete manual.
579 .\\" DO NOT MODIFY THIS FILE! It was generated by $this_program $this_version.
580 .TH $PROGRAM "$section" "$date" "$source" "$manual"
584 my @pre = (_
('NAME'), _
('SYNOPSIS'), _
('DESCRIPTION'), _
('OPTIONS'),
587 my @post = (_
('AUTHOR'), _
('REPORTING BUGS'), _
('COPYRIGHT'), _
('SEE ALSO'));
588 my $filter = join '|', @pre, @post;
591 for my $sect (@pre, (grep ! /^($filter)$/o, @include), @post)
595 my $lsect = gettext
$sect;
596 my $quote = $lsect =~ /\W/ ?
'"' : '';
597 print ".SH $quote$lsect$quote\n";
599 for ($include{$sect})
601 # Replace leading dot, apostrophe, backslash and hyphen
608 # Convert some latin1 chars to troff equivalents
609 s/\xa0/\\ /g; # non-breaking space
616 close STDOUT
or kark N_
("%s: error writing to %s (%s)"), $this_program,
617 $opt_output || 'stdout', $!;
621 # Convert option dashes to \- to stop nroff from hyphenating 'em, and
622 # embolden. Option arguments get italicised.
625 local $_ = '\fB' . shift;
628 unless (s/\[=(.*)\]$/\\fR[=\\fI$1\\fR]/)