3 # Generate a short man page from --help and --version output.
4 # Copyright (C) 1997-2005, 2009-2011, 2013, 2015-2021 Free Software Foundation,
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 3, 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);
30 my $this_program = 'help2man';
31 my $this_version = '1.40.4';
37 die "$this_program: no locale support (Locale::gettext required)\n"
38 unless $locale eq 'C';
43 sub enc_user { $_[0] }
44 sub kark { die +(sprintf shift, @_), "\n" }
47 my $version_info = enc_user sprintf _(<<'EOT'), $this_program, $this_version;
50 Copyright (C) 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2009, 2010,
51 2011 Free Software Foundation, Inc.
52 This is free software; see the source for copying conditions. There is NO
53 warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
55 Written by Brendan O'Dea <bod@debian.org>
58 my $help_info = enc_user sprintf _(<<'EOT'), $this_program, $this_program;
59 '%s' generates a man page out of '--help' and '--version' output.
61 Usage: %s [OPTION]... EXECUTABLE
63 -n, --name=STRING description for the NAME paragraph
64 -s, --section=SECTION section number for manual page (1, 6, 8)
65 -m, --manual=TEXT name of manual (User Commands, ...)
66 -S, --source=TEXT source of program (FSF, Debian, ...)
67 -L, --locale=STRING select locale (default "C")
68 -i, --include=FILE include material from 'FILE'
69 -I, --opt-include=FILE include material from 'FILE' if it exists
70 -o, --output=FILE send output to 'FILE'
71 -p, --info-page=TEXT name of Texinfo manual
72 -N, --no-info suppress pointer to Texinfo manual
73 -l, --libtool exclude the 'lt-' from the program name
74 --help print this help, then exit
75 --version print version number, then exit
77 EXECUTABLE should accept '--help' and '--version' options and produce output on
78 stdout although alternatives may be specified using:
80 -h, --help-option=STRING help option string
81 -v, --version-option=STRING version option string
82 --version-string=STRING version string
83 --no-discard-stderr include stderr when parsing option output
85 Report bugs to <bug-help2man@gnu.org>.
91 my $help_option = '--help';
92 my $version_option = '--version';
93 my $discard_stderr = 1;
94 my ($opt_name, @opt_include, $opt_output, $opt_info, $opt_no_info, $opt_libtool,
98 'n|name=s' => \$opt_name,
99 's|section=s' => \$section,
100 'm|manual=s' => \$manual,
101 'S|source=s' => \$source,
102 'L|locale=s' => sub { configure_locale pop },
103 'i|include=s' => sub { push @opt_include, [ pop, 1 ] },
104 'I|opt-include=s' => sub { push @opt_include, [ pop, 0 ] },
105 'o|output=s' => \$opt_output,
106 'p|info-page=s' => \$opt_info,
107 'N|no-info' => \$opt_no_info,
108 'l|libtool' => \$opt_libtool,
109 'help' => sub { print $help_info; exit },
110 'version' => sub { print $version_info; exit },
111 'h|help-option=s' => \$help_option,
112 'v|version-option=s' => \$version_option,
113 'version-string=s' => \$version_text,
114 'discard-stderr!' => \$discard_stderr,
118 Getopt::Long::config('bundling');
119 die $help_info unless GetOptions %opt_def and @ARGV == 1;
123 my @include = (); # retain order given in include file
125 # Process include file (if given). Format is:
138 my ($inc, $required) = @{shift @opt_include};
140 next unless -f $inc or $required;
141 kark N_("%s: can't open '%s' (%s)"), $this_program, $inc, $!
142 unless open INC, $inc;
145 my $hash = \%include;
149 # Convert input to internal Perl format, so that multibyte
150 # sequences are treated as single characters.
154 if (/^\[([^]]+)\]\s*$/)
160 push @include, $key unless $include{$key};
165 if (m!^/(.*)/([ims]*)\s*$!)
167 my $pat = $2 ? "(?$2)$1" : $1;
170 eval { $key = qr($pat) };
173 $@ =~ s/ at .*? line \d.*//;
181 # Check for options before the first section--anything else is
182 # silently ignored, allowing the first for comments and
196 $hash->{$key} ||= '';
202 kark N_("%s: no valid information found in '%s'"), $this_program, $inc
206 # Compress trailing blank lines.
207 for my $hash (\(%include, %append))
209 for (keys %$hash) { $hash->{$_} =~ s/\n+$/\n/ }
212 sub get_option_value;
214 # Grab help and version info from executable.
215 my $help_text = get_option_value $ARGV[0], $help_option;
216 $version_text ||= get_option_value $ARGV[0], $version_option;
218 # Translators: the following message is a strftime(3) format string, which in
219 # the English version expands to the month as a word and the full year. It
220 # is used on the footer of the generated manual pages. If in doubt, you may
221 # just use %x as the value (which should be the full locale-specific date).
222 my $date = enc strftime _("%B %Y"), localtime;
223 (my $program = $ARGV[0]) =~ s!.*/!!;
224 my $package = $program;
229 unlink $opt_output or kark N_("%s: can't unlink %s (%s)"),
230 $this_program, $opt_output, $! if -e $opt_output;
232 open STDOUT, ">$opt_output"
233 or kark N_("%s: can't create %s (%s)"), $this_program, $opt_output, $!;
236 # The first line of the --version information is assumed to be in one
237 # of the following formats:
240 # <program> <version>
241 # {GNU,Free} <program> <version>
242 # <program> ({GNU,Free} <package>) <version>
243 # <program> - {GNU,Free} <package> <version>
245 # and separated from any copyright/author details by a blank line.
247 ($_, $version_text) = ((split /\n+/, $version_text, 2), '');
249 if (/^(\S+) +\(((?:GNU|Free) +[^)]+)\) +(.*)/ or
250 /^(\S+) +- *((?:GNU|Free) +\S+) +(.*)/)
256 elsif (/^((?:GNU|Free) +)?(\S+) +(.*)/)
259 $package = $1 ? "$1$2" : $2;
269 # No info for 'info' itself.
270 $opt_no_info = 1 if $program eq 'info';
272 # Translators: "NAME", "SYNOPSIS" and other one or two word strings in all
273 # upper case are manual page section headings. The man(1) manual page in your
274 # language, if available should provide the conventional translations.
275 for ($include{_('NAME')})
277 if ($opt_name) # --name overrides --include contents.
279 $_ = "$program \\- $opt_name\n";
281 elsif ($_) # Use first name given as $program
283 $program = $1 if /^([^\s,]+)(?:,?\s*[^\s,\\-]+)*\s+\\?-/;
285 else # Set a default (useless) NAME paragraph.
287 $_ = sprintf _("%s \\- manual page for %s %s") . "\n", $program,
292 # Man pages traditionally have the page title in caps.
293 my $PROGRAM = uc $program;
295 # Set default page head/footers
296 $source ||= "$program $version";
301 if (/^(1[Mm]|8)/) { $manual = enc _('System Administration Utilities') }
302 elsif (/^6/) { $manual = enc _('Games') }
303 else { $manual = enc _('User Commands') }
307 # Extract usage clause(s) [if any] for SYNOPSIS.
308 # Translators: "Usage" and "or" here are patterns (regular expressions) which
309 # are used to match the usage synopsis in program output. An example from cp
310 # (GNU coreutils) which contains both strings:
311 # Usage: cp [OPTION]... [-T] SOURCE DEST
312 # or: cp [OPTION]... SOURCE... DIRECTORY
313 # or: cp [OPTION]... -t DIRECTORY SOURCE...
314 my $PAT_USAGE = _('Usage');
315 my $PAT_USAGE_CONT = _('or');
316 if ($help_text =~ s/^($PAT_USAGE):( +(\S+))(.*)((?:\n(?: {6}\1| *($PAT_USAGE_CONT): +\S).*)*)//om)
323 for (split /\n/) { s/^ *(($PAT_USAGE_CONT): +)?//o; push @syn, $_ }
329 $synopsis .= ".br\n" if $synopsis;
331 s/^lt-// if $opt_libtool;
333 $synopsis .= ".B $1\n";
335 s/(([][]|\.\.+)+)/\\fR$1\\fI/g;
336 s/^/\\fI/ unless s/^\\fR//;
347 $include{_('SYNOPSIS')} ||= $synopsis;
350 # Process text, initial section is DESCRIPTION.
351 my $sect = _('DESCRIPTION');
352 $_ = "$help_text\n\n$version_text";
354 # Normalise paragraph breaks.
359 # Join hyphenated lines.
360 s/([A-Za-z])-\n *([A-Za-z])/$1$2/g;
362 # Temporarily exchange leading dots, apostrophes and backslashes for
368 # Translators: patterns are used to match common program output. In the source
369 # these strings are all of the form of "my $PAT_something = _('...');" and are
370 # regular expressions. If there is more than one commonly used string, you
371 # may separate alternatives with "|". Spaces in these expressions are written
372 # as " +" to indicate that more than one space may be matched. The string
373 # "(?:[\\w-]+ +)?" in the bug reporting pattern is used to indicate an
374 # optional word, so that either "Report bugs" or "Report _program_ bugs" will
376 my $PAT_BUGS = _('Report +(?:[\w-]+ +)?bugs|Email +bug +reports +to');
377 my $PAT_AUTHOR = _('Written +by');
378 my $PAT_OPTIONS = _('Options');
379 my $PAT_ENVIRONMENT = _('Environment');
380 my $PAT_FILES = _('Files');
381 my $PAT_EXAMPLES = _('Examples');
382 my $PAT_FREE_SOFTWARE = _('This +is +free +software');
384 # Start a new paragraph (if required) for these.
385 s/([^\n])\n($PAT_BUGS|$PAT_AUTHOR) /$1\n\n$2 /og;
387 # Convert iso-8859-1 copyright symbol or (c) to nroff
389 s/^Copyright +(?:\xa9|\([Cc]\))/Copyright \\(co/mg;
395 # Convert some standard paragraph names.
396 if (s/^($PAT_OPTIONS): *\n//o)
398 $sect = _('OPTIONS');
401 if (s/^($PAT_ENVIRONMENT): *\n//o)
403 $sect = _('ENVIRONMENT');
406 if (s/^($PAT_FILES): *\n//o)
411 elsif (s/^($PAT_EXAMPLES): *\n//o)
413 $sect = _('EXAMPLES');
420 $sect = _('COPYRIGHT');
423 # Bug reporting section.
424 elsif (/^($PAT_BUGS) /o)
426 $sect = _('REPORTING BUGS');
430 elsif (/^($PAT_AUTHOR)/o)
435 # Examples, indicated by an indented leading $, % or > are
436 # rendered in a constant width font.
437 if (/^( +)([\$\%>] )\S/)
442 $include{$sect} ||= '';
443 while (s/^$indent\Q$prefix\E(\S.*)\n*//)
445 $include{$sect} .= "$break\n\\f(CW$prefix$1\\fR\n";
453 $include{$sect} ||= '';
455 # Sub-sections have a trailing colon and the second line indented.
456 if (s/^(\S.*:) *\n / /)
458 $matched .= $& if %append;
459 $include{$sect} .= qq(.SS "$1"\n);
465 # Option with description.
466 if (s/^( {1,10}([+-]\S.*?))(?:( +(?!-))|\n( {20,}))(\S.*)\n//)
468 $matched .= $& if %append;
469 $indent = length ($4 || "$1$3");
470 $content = ".TP\n\x84$2\n\x84$5\n";
473 # Indent may be different on second line.
474 $indent = length $& if /^ {20,}/;
478 # Option without description.
479 elsif (s/^ {1,10}([+-]\S.*)\n//)
481 $matched .= $& if %append;
482 $content = ".HP\n\x84$1\n";
483 $indent = 80; # not continued
486 # Indented paragraph with tag.
487 elsif (s/^( +(\S.*?) +)(\S.*)\n//)
489 $matched .= $& if %append;
491 $content = ".TP\n\x84$2\n\x84$3\n";
494 # Indented paragraph.
495 elsif (s/^( +)(\S.*)\n//)
497 $matched .= $& if %append;
499 $content = ".IP\n\x84$2\n";
502 # Left justified paragraph.
506 $matched .= $& if %append;
507 $content = ".PP\n" if $include{$sect};
511 # Append continuations.
512 while ($indent ? s/^ {$indent}(\S.*)\n// : s/^(\S.*)\n//)
514 $matched .= $& if %append;
515 $content .= "\x84$1\n";
518 # Move to next paragraph.
523 # Leading dot and apostrophe protection.
529 s/(^| |\()(-[][\w=-]+)/$1 . convert_option $2/mge;
531 # Escape remaining hyphens
534 if ($sect eq 'COPYRIGHT')
536 # Insert line breaks before additional copyright messages
537 # and the disclaimer.
538 s/\n(Copyright |$PAT_FREE_SOFTWARE)/\n.br\n$1/og;
540 elsif ($sect eq 'REPORTING BUGS')
542 # Handle multi-line bug reporting sections of the form:
544 # Report <program> bugs to <addr>
545 # GNU <package> home page: <url>
547 s/\n([[:upper:]])/\n.br\n$1/g;
551 # Check if matched paragraph contains /pat/.
554 for my $pat (keys %append)
556 if ($matched =~ $pat)
558 $content .= ".PP\n" unless $append{$pat} =~ /^\./;
559 $content .= $append{$pat};
564 $include{$sect} .= $content;
567 # Refer to the real documentation.
568 unless ($opt_no_info)
570 my $info_page = $opt_info || $program;
572 $sect = _('SEE ALSO');
573 $include{$sect} ||= '';
574 $include{$sect} .= ".PP\n" if $include{$sect};
575 $include{$sect} .= sprintf _(<<'EOT'), $program, $program, $info_page;
576 The full documentation for
578 is maintained as a Texinfo manual. If the
582 programs are properly installed at your site, the command
586 should give you access to the complete manual.
592 .\\" DO NOT MODIFY THIS FILE! It was generated by $this_program $this_version.
593 .TH $PROGRAM "$section" "$date" "$source" "$manual"
597 my @pre = (_('NAME'), _('SYNOPSIS'), _('DESCRIPTION'), _('OPTIONS'),
598 _('ENVIRONMENT'), _('FILES'), _('EXAMPLES'));
600 my @post = (_('AUTHOR'), _('REPORTING BUGS'), _('COPYRIGHT'), _('SEE ALSO'));
601 my $filter = join '|', @pre, @post;
604 for my $sect (@pre, (grep ! /^($filter)$/o, @include), @post)
608 my $quote = $sect =~ /\W/ ? '"' : '';
609 print enc ".SH $quote$sect$quote\n";
611 for ($include{$sect})
613 # Replace leading dot, apostrophe, backslash and hyphen
620 # Convert some latin1 chars to troff equivalents
621 s/\xa0/\\ /g; # non-breaking space
628 close STDOUT or kark N_("%s: error writing to %s (%s)"), $this_program,
629 $opt_output || 'stdout', $!;
633 # Call program with given option and return results.
636 my ($prog, $opt) = @_;
637 my $stderr = $discard_stderr ? '/dev/null' : '&1';
639 map { s/ +$//; expand $_ }
641 `$prog $opt 2>$stderr`;
645 my $err = N_("%s: can't get '%s' info from %s%s");
646 my $extra = $discard_stderr
647 ? "\n" . N_("Try '--no-discard-stderr' if option outputs to stderr")
650 kark $err, $this_program, $opt, $prog, $extra;
656 # Convert option dashes to \- to stop nroff from hyphenating 'em, and
657 # embolden. Option arguments get italicised.
660 local $_ = '\fB' . shift;
663 unless (s/\[=(.*)\]$/\\fR[=\\fI$1\\fR]/)