3 # Generate a short man page from --help and --version output.
4 # Copyright (C) 1997, 1998, 1999, 2000, 2001, 2002, 2003 Free Software
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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, 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.33';
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 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 # --name overrides --include contents.
287 $include{_
('NAME')} = "$program \\- $opt_name\n" if $opt_name;
289 # Default (useless) NAME paragraph.
290 $include{_
('NAME')} ||= sprintf _
("%s \\- manual page for %s %s") . "\n",
291 $program, $program, $version;
293 # Man pages traditionally have the page title in caps.
294 my $PROGRAM = uc $program;
296 # Set default page head/footers
297 $source ||= "$program $version";
302 if (/^(1[Mm]|8)/) { $manual = _
('System Administration Utilities') }
303 elsif (/^6/) { $manual = _
('Games') }
304 else { $manual = _
('User Commands') }
308 # Extract usage clause(s) [if any] for SYNOPSIS.
309 my $PAT_USAGE = _
('Usage');
310 my $PAT_USAGE_CONT = _
('or');
311 if ($help_text =~ s/^($PAT_USAGE):( +(\S+))(.*)((?:\n(?: {6}\1| *($PAT_USAGE_CONT): +\S).*)*)//om)
318 for (split /\n/) { s/^ *(($PAT_USAGE_CONT): +)?//o; push @syn, $_ }
324 $synopsis .= ".br\n" if $synopsis;
327 $synopsis .= ".B $1\n";
329 s/(([][]|\.\.+)+)/\\fR$1\\fI/g;
330 s/^/\\fI/ unless s/^\\fR//;
341 $include{_
('SYNOPSIS')} ||= $synopsis;
344 # Process text, initial section is DESCRIPTION.
345 my $sect = _
('DESCRIPTION');
346 $_ = "$help_text\n\n$version_text";
348 # Normalise paragraph breaks.
353 # Temporarily exchange leading dots, apostrophes and backslashes for
359 my $PAT_BUGS = _
('Report +bugs|Email +bug +reports +to');
360 my $PAT_AUTHOR = _
('Written +by');
361 my $PAT_OPTIONS = _
('Options');
362 my $PAT_EXAMPLES = _
('Examples');
363 my $PAT_FREE_SOFTWARE = _
('This +is +free +software');
365 # Start a new paragraph (if required) for these.
366 s/([^\n])\n($PAT_BUGS|$PAT_AUTHOR)/$1\n\n$2/og;
372 # Convert some standard paragraph names.
373 if (s/^($PAT_OPTIONS): *\n//o)
375 $sect = _
('OPTIONS');
378 elsif (s/^($PAT_EXAMPLES): *\n//o)
380 $sect = _
('EXAMPLES');
385 if (/^Copyright +[(\xa9]/)
387 $sect = _
('COPYRIGHT');
388 $include{$sect} ||= '';
389 $include{$sect} .= ".PP\n" if $include{$sect};
392 ($copy, $_) = split /\n\n/, $_, 2;
399 # Convert iso9959-1 copyright symbol or (c) to nroff
401 s/^Copyright +(?:\xa9|\([Cc]\))/Copyright \\(co/mg;
403 # Insert line breaks before additional copyright messages
404 # and the disclaimer.
405 s/(.)\n(Copyright |$PAT_FREE_SOFTWARE)/$1\n.br\n$2/og;
407 # Join hyphenated lines.
408 s/([A-Za-z])-\n */$1/g;
411 $include{$sect} .= $copy;
416 # Catch bug report text.
417 if (/^($PAT_BUGS) /o)
419 $sect = _
('REPORTING BUGS');
423 elsif (/^($PAT_AUTHOR)/o)
428 # Examples, indicated by an indented leading $, % or > are
429 # rendered in a constant width font.
430 if (/^( +)([\$\%>] )\S/)
435 $include{$sect} ||= '';
436 while (s/^$indent\Q$prefix\E(\S.*)\n*//)
438 $include{$sect} .= "$break\n\\f(CW$prefix$1\\fR\n";
446 $include{$sect} ||= '';
448 # Sub-sections have a trailing colon and the second line indented.
449 if (s/^(\S.*:) *\n / /)
451 $matched .= $& if %append;
452 $include{$sect} .= qq(.SS
"$1"\n);
458 # Option with description.
459 if (s/^( {1,10}([+-]\S.*?))(?:( +(?!-))|\n( {20,}))(\S.*)\n//)
461 $matched .= $& if %append;
462 $indent = length ($4 || "$1$3");
463 $content = ".TP\n\x83$2\n\x83$5\n";
466 # Indent may be different on second line.
467 $indent = length $& if /^ {20,}/;
471 # Option without description.
472 elsif (s/^ {1,10}([+-]\S.*)\n//)
474 $matched .= $& if %append;
475 $content = ".HP\n\x83$1\n";
476 $indent = 80; # not continued
479 # Indented paragraph with tag.
480 elsif (s/^( +(\S.*?) +)(\S.*)\n//)
482 $matched .= $& if %append;
484 $content = ".TP\n\x83$2\n\x83$3\n";
487 # Indented paragraph.
488 elsif (s/^( +)(\S.*)\n//)
490 $matched .= $& if %append;
492 $content = ".IP\n\x83$2\n";
495 # Left justified paragraph.
499 $matched .= $& if %append;
500 $content = ".PP\n" if $include{$sect};
504 # Append continuations.
505 while ($indent ?
s/^ {$indent}(\S.*)\n// : s/^(\S.*)\n//)
507 $matched .= $& if %append;
508 $content .= "\x83$1\n"
511 # Move to next paragraph.
516 # Leading dot and apostrophe protection.
522 s/(^| )(-[][\w=-]+)/$1 . convert_option $2/mge;
525 # Check if matched paragraph contains /pat/.
528 for my $pat (keys %append)
530 if ($matched =~ $pat)
532 $content .= ".PP\n" unless $append{$pat} =~ /^\./;
533 $content .= $append{$pat};
538 $include{$sect} .= $content;
541 # Refer to the real documentation.
542 unless ($opt_no_info)
544 my $info_page = $opt_info || $program;
546 $sect = _
('SEE ALSO');
547 $include{$sect} ||= '';
548 $include{$sect} .= ".PP\n" if $include{$sect};
549 $include{$sect} .= sprintf _
(<<'EOT'), $program, $program, $info_page;
550 The full documentation for
552 is maintained as a Texinfo manual. If the
556 programs are properly installed at your site, the command
560 should give you access to the complete manual.
566 .\\" DO NOT MODIFY THIS FILE! It was generated by $this_program $this_version.
567 .TH $PROGRAM "$section" "$date" "$source" "$manual"
571 my @pre = (_
('NAME'), _
('SYNOPSIS'), _
('DESCRIPTION'), _
('OPTIONS'),
574 my @post = (_
('AUTHOR'), _
('REPORTING BUGS'), _
('COPYRIGHT'), _
('SEE ALSO'));
575 my $filter = join '|', @pre, @post;
578 for my $sect (@pre, (grep ! /^($filter)$/o, @include), @post)
582 my $lsect = gettext
$sect;
583 my $quote = $lsect =~ /\W/ ?
'"' : '';
584 print ".SH $quote$lsect$quote\n";
586 for ($include{$sect})
588 # Replace leading dot, apostrophe and backslash tokens.
593 # Convert some latin1 chars to troff equivalents
594 s/\xa0/\\ /g; # non-breaking space
601 close STDOUT
or kark N_
("%s: error writing to %s (%s)"), $this_program,
602 $opt_output || 'stdout', $!;
606 # Convert option dashes to \- to stop nroff from hyphenating 'em, and
607 # embolden. Option arguments get italicised.
610 local $_ = '\fB' . shift;
613 unless (s/\[=(.*)\]$/\\fR[=\\fI$1\\fR]/)