4 # Self extracting help2man script.
6 # -q, --quiet Suppress extraction message
7 # -s, --stdout Extract to stdout
8 # -w, --with-gettext Add support for localized man pages
9 # -n, --name Print name only*
10 # -v, --version Print version only*
19 my ($program, $version) = ('help2man', '1.48.3');
22 die "Usage: $0 [--quiet] [--stdout] [--with-gettext] [--name] [--version]\n"
23 unless GetOptions \%opts, qw(quiet stdout with-gettext name version)
26 print "$program\n" if $opts{name};
27 print "$version\n" if $opts{version};
28 exit if $opts{name} or $opts{version};
40 $target =~ s/\.PL$// or die "$0: can't determine target name\n";
41 $tmp = "$target.tmp$$";
42 unlink $tmp or die "$0: can't unlink $tmp ($!)\n" if -e $tmp;
43 open OUT, ">$tmp" or die "$0: can't create $tmp ($!)\n";
46 print "Extracting $target (with variable substitutions)\n"
50 print OUT "$Config{startperl} -w\n";
52 # For systems without the crash-bang hack also add:
53 print OUT <<"!GROK!THIS!" if $Config{sharpbang} !~ /^#!/;
54 eval 'exec $Config{perlpath} -wS \$0 \${1+"\$@"}'
55 if \$running_under_some_shell;
57 \$running_under_some_shell = 0; # for -w
60 # No substitutions for this chunk:
61 print OUT <<'!NO!SUBS!';
63 # Generate a short man page from --help and --version output.
64 # Copyright (C) 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2009,
65 # 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2020, 2021 Free Software
68 # This program is free software; you can redistribute it and/or modify
69 # it under the terms of the GNU General Public License as published by
70 # the Free Software Foundation; either version 3, or (at your option)
73 # This program is distributed in the hope that it will be useful,
74 # but WITHOUT ANY WARRANTY; without even the implied warranty of
75 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
76 # GNU General Public License for more details.
78 # You should have received a copy of the GNU General Public License
79 # along with this program; if not, see <http://www.gnu.org/licenses/>.
81 # Written by Brendan O'Dea <bod@debian.org>
82 # Available from ftp://ftp.gnu.org/gnu/help2man/
87 use Text::ParseWords qw(shellwords);
88 use Text::Tabs qw(expand);
89 use POSIX qw(strftime setlocale LC_ALL);
92 print OUT <<'!NO!SUBS!' if $opts{'with-gettext'};
93 use Locale::gettext qw(gettext);
94 use Encode qw(decode encode);
95 use I18N::Langinfo qw(langinfo CODESET);
98 # Interpolate program name and version:
99 print OUT <<"!GROK!THIS!";
101 my \$this_program = '$program';
102 my \$this_version = '$version';
105 # Conditionally include gettext support:
106 print OUT $opts{'with-gettext'} ? <<'!WITH!GETTEXT!' : <<'!NO!GETTEXT!';
110 my $gettext = Locale::gettext->domain($this_program);
111 sub _ { $gettext->get($_[0]) }
113 my ($user_locale) = grep defined && length,
114 (map $ENV{$_}, qw(LANGUAGE LC_ALL LC_MESSAGES LANG)), 'C';
116 my $user_encoding = langinfo CODESET;
118 # Set localisation of date and executable's output.
121 delete @ENV{qw(LANGUAGE LC_MESSAGES LANG)};
122 setlocale LC_ALL, $ENV{LC_ALL} = shift || 'C';
123 $encoding = langinfo CODESET;
126 sub dec { $encoding ? decode $encoding, $_[0] : $_[0] }
127 sub enc { $encoding ? encode $encoding, $_[0] : $_[0] }
128 sub enc_user { encode $user_encoding, $_[0] }
129 sub kark # die with message formatted in the invoking user's locale
131 setlocale LC_ALL, $user_locale;
132 my $fmt = $gettext->get(shift);
133 my $errmsg = enc_user sprintf $fmt, @_;
144 die "$this_program: no locale support (Locale::gettext required)\n"
145 unless $locale eq 'C';
150 sub enc_user { $_[0] }
151 sub kark { die +(sprintf shift, @_), "\n" }
154 # No substitutions for this chunk:
155 print OUT <<'!NO!SUBS!';
158 sub program_basename;
159 sub get_option_value;
161 sub fix_italic_spacing;
163 my $version_info = enc_user sprintf _(<<'EOT'), $this_program, $this_version;
166 Copyright (C) 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2009,
167 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2020, 2021 Free Software
169 This is free software; see the source for copying conditions. There is NO
170 warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
172 Written by Brendan O'Dea <bod@debian.org>
175 my $help_info = enc_user sprintf _(<<'EOT'), $this_program, $this_program;
176 `%s' generates a man page out of `--help' and `--version' output.
178 Usage: %s [OPTION]... EXECUTABLE
180 -n, --name=STRING description for the NAME paragraph
181 -s, --section=SECTION section number for manual page (1, 6, 8)
182 -m, --manual=TEXT name of manual (User Commands, ...)
183 -S, --source=TEXT source of program (FSF, Debian, ...)
184 -L, --locale=STRING select locale (default "C")
185 -i, --include=FILE include material from `FILE'
186 -I, --opt-include=FILE include material from `FILE' if it exists
187 -o, --output=FILE send output to `FILE'
188 -p, --info-page=TEXT name of Texinfo manual
189 -N, --no-info suppress pointer to Texinfo manual
190 -l, --libtool exclude the `lt-' from the program name
191 --help print this help, then exit
192 --version print version number, then exit
194 EXECUTABLE should accept `--help' and `--version' options and produce output on
195 stdout although alternatives may be specified using:
197 -h, --help-option=STRING help option string
198 -v, --version-option=STRING version option string
199 --version-string=STRING version string
200 --no-discard-stderr include stderr when parsing option output
202 Report bugs to <bug-help2man@gnu.org>.
208 my $help_option = '--help';
209 my $version_option = '--version';
210 my $discard_stderr = 1;
211 my ($opt_name, @opt_include, $opt_output, $opt_info, $opt_no_info, $opt_libtool,
215 'n|name=s' => \$opt_name,
216 's|section=s' => \$section,
217 'm|manual=s' => \$manual,
218 'S|source=s' => \$source,
219 'L|locale=s' => sub { configure_locale pop },
220 'i|include=s' => sub { push @opt_include, [ pop, 1 ] },
221 'I|opt-include=s' => sub { push @opt_include, [ pop, 0 ] },
222 'o|output=s' => \$opt_output,
223 'p|info-page=s' => \$opt_info,
224 'N|no-info' => \$opt_no_info,
225 'l|libtool' => \$opt_libtool,
226 'help' => sub { print $help_info; exit },
227 'version' => sub { print $version_info; exit },
228 'h|help-option=s' => \$help_option,
229 'v|version-option=s' => \$version_option,
230 'version-string=s' => \$version_text,
231 'discard-stderr!' => \$discard_stderr,
235 Getopt::Long::config('bundling');
236 die $help_info unless GetOptions %opt_def and @ARGV == 1;
240 print OUT <<'!NO!SUBS!' if $opts{'with-gettext'};
241 configure_locale unless $encoding;
245 # No substitutions for the remainder of the script:
246 print OUT <<'!NO!SUBS!';
250 my %append_match = ();
251 my @sections = (); # retain order of include file or in-line *section*s
253 # Process include file (if given). Format is:
255 # Optional initial text, ignored. May include lines starting with `-'
256 # which are processed as options.
259 # Verbatim text to be included in the named section. By default at
260 # the start, but in the case of `name' and `synopsis' the content
261 # will replace the autogenerated contents.
264 # Verbatim text to be inserted at the start of the named section.
267 # Verbatim text to replace the named section.
270 # Verbatim text to be appended to the end of the named section.
273 # Verbatim text for inclusion below a paragraph matching `pattern'.
278 my ($inc, $required) = @{shift @opt_include};
280 next unless -f $inc or $required;
281 kark N_("%s: can't open `%s' (%s)"), $this_program, $inc, $!
282 unless open INC, $inc;
289 # Convert input to internal Perl format, so that multibyte
290 # sequences are treated as single characters.
294 if (/^\[([^]]+)\]\s*$/)
300 # Handle explicit [<section], [=section] and [>section]
301 if ($key =~ s/^([<>=])\s*//)
303 if ($1 eq '>') { $hash = \%append; }
304 elsif ($1 eq '=') { $hash = \%replace; }
306 # NAME/SYNOPSIS replace by default
307 elsif ($key eq _('NAME') or $key eq _('SYNOPSIS'))
316 push @sections, $key;
321 if (m!^/(.*)/([ims]*)\s*$!)
323 my $pat = $2 ? "(?$2)$1" : $1;
326 eval { $key = qr($pat) };
329 $@ =~ s/ at .*? line \d.*//;
333 $hash = \%append_match;
337 # Check for options before the first section--anything else is
338 # silently ignored, allowing the first for comments and
345 local @ARGV = shellwords $_;
357 kark N_("%s: no valid information found in `%s'"), $this_program, $inc
361 # Compress trailing blank lines.
362 for my $hash (\(%include, %replace, %append, %append_match))
364 for (keys %$hash) { $hash->{$_} =~ s/\n+$/\n/ }
367 # Grab help and version info from executable.
368 my $help_text = get_option_value $ARGV[0], $help_option;
369 $version_text ||= get_option_value $ARGV[0], $version_option;
371 # By default the generated manual pages will include the current date. This may
372 # however be overriden by setting the environment variable $SOURCE_DATE_EPOCH to
373 # an integer value of the seconds since the UNIX epoch. This is primarily
374 # intended to support reproducible builds (wiki.debian.org/ReproducibleBuilds)
375 # and will additionally ensure that the output date string is UTC.
376 my $epoch_secs = time;
377 if (exists $ENV{SOURCE_DATE_EPOCH} and $ENV{SOURCE_DATE_EPOCH} =~ /^(\d+)$/)
383 # Translators: the following message is a strftime(3) format string, which in
384 # the English version expands to the month as a word and the full year. It
385 # is used on the footer of the generated manual pages. If in doubt, you may
386 # just use %x as the value (which should be the full locale-specific date).
387 my $date = enc strftime _("%B %Y"), localtime $epoch_secs;
388 my $program = program_basename $ARGV[0];
389 my $package = $program;
394 unlink $opt_output or kark N_("%s: can't unlink %s (%s)"),
395 $this_program, $opt_output, $! if -e $opt_output;
397 open STDOUT, ">$opt_output"
398 or kark N_("%s: can't create %s (%s)"), $this_program, $opt_output, $!;
401 # The first line of the --version information is assumed to be in one
402 # of the following formats:
405 # <program> <version>
406 # {GNU,Free} <program> <version>
407 # <program> ({GNU,Free,} <package>) <version>
408 # <program> - {GNU,Free,} <package> <version>
409 # <program> - {GNU,Free,} <package> - <version>
411 # and separated from any copyright/author details by a blank line.
413 ($_, $version_text) = ((split /\n+/, $version_text, 2), '');
415 if (/^(\S+) +\(((?:(?:GNU|Free) +)?[^)]+)\) +(\S.*)$/ or
416 /^(\S+) +- +((?:(?:GNU|Free) +)?\S.*) +- +(\S.*)$/ or
417 /^(\S+) +- +((?:(?:GNU|Free) +)?\S+) +(\S.*)$/)
419 $program = program_basename $1;
423 elsif (/^((?:GNU|Free) +)?(\S+) +(\S.*)$/)
425 $program = program_basename $2;
426 $package = $1 ? "$1$program" : $program;
434 # No info for `info' itself.
435 $opt_no_info = 1 if $program eq 'info';
439 # --name overrides --include contents.
440 $replace{_('NAME')} = "$program \\- $opt_name\n";
443 # Translators: "NAME", "SYNOPSIS" and other one or two word strings in all
444 # upper case are manual page section headings. The man(1) manual page in your
445 # language, if available should provide the conventional translations.
446 for ($replace{_('NAME')} || ($include{_('NAME')} ||= ''))
448 if ($_) # Use first name given as $program
450 $program = $1 if /^([^\s,]+)(?:,?\s*[^\s,\\-]+)*\s+\\?-/;
452 else # Set a default (useless) NAME paragraph.
454 $_ = sprintf _("%s \\- manual page for %s %s") . "\n", $program,
459 # Man pages traditionally have the page title in caps.
460 my $PROGRAM = uc $program;
462 # Set default page head/footers
463 $source ||= "$package $version";
468 if (/^(1[Mm]|8)/) { $manual = enc _('System Administration Utilities') }
469 elsif (/^6/) { $manual = enc _('Games') }
470 else { $manual = enc _('User Commands') }
474 # Extract usage clause(s) [if any] for SYNOPSIS.
475 # Translators: "Usage" and "or" here are patterns (regular expressions) which
476 # are used to match the usage synopsis in program output. An example from cp
477 # (GNU coreutils) which contains both strings:
478 # Usage: cp [OPTION]... [-T] SOURCE DEST
479 # or: cp [OPTION]... SOURCE... DIRECTORY
480 # or: cp [OPTION]... -t DIRECTORY SOURCE...
481 my $PAT_USAGE = _('Usage');
482 my $PAT_USAGE_CONT = _('or');
483 if ($help_text =~ s/^($PAT_USAGE):( +(\S+))(.*)((?:\n(?: {6}\1| *($PAT_USAGE_CONT): +\S).*)*)//om)
490 for (split /\n/) { s/^ *(($PAT_USAGE_CONT): +)?//o; push @syn, $_ }
496 $synopsis .= ".br\n" if $synopsis;
498 s/^lt-// if $opt_libtool;
500 $synopsis .= ".B $1\n";
502 s/(([][]|\.\.+)+)/\\fR$1\\fI/g;
503 s/^/\\fI/ unless s/^\\fR//;
511 $_ = fix_italic_spacing $_;
515 $include{_('SYNOPSIS')} .= $synopsis;
518 # Process text, initial section is DESCRIPTION.
519 my $sect = _('DESCRIPTION');
520 $_ = "$help_text\n\n$version_text";
522 # Normalise paragraph breaks.
527 # Join hyphenated lines.
528 s/([A-Za-z])-\n *([A-Za-z])/$1$2/g;
530 # Temporarily exchange leading dots, apostrophes and backslashes for
536 # Translators: patterns are used to match common program output. In the source
537 # these strings are all of the form of "my $PAT_something = _('...');" and are
538 # regular expressions. If there is more than one commonly used string, you
539 # may separate alternatives with "|". Spaces in these expressions are written
540 # as " +" to indicate that more than one space may be matched. The string
541 # "(?:[\\w-]+ +)?" in the bug reporting pattern is used to indicate an
542 # optional word, so that either "Report bugs" or "Report _program_ bugs" will
544 my $PAT_BUGS = _('Report +(?:[\w-]+ +)?bugs|Email +bug +reports +to');
545 my $PAT_AUTHOR = _('Written +by');
546 my $PAT_OPTIONS = _('Options');
547 my $PAT_ENVIRONMENT = _('Environment');
548 my $PAT_FILES = _('Files');
549 my $PAT_EXAMPLES = _('Examples');
550 my $PAT_FREE_SOFTWARE = _('This +is +free +software');
552 # Start a new paragraph (if required) for these.
553 s/([^\n])\n($PAT_BUGS|$PAT_AUTHOR) /$1\n\n$2 /og;
555 # Convert iso-8859-1 copyright symbol or (c) to nroff
557 s/^Copyright +(?:\xa9|\([Cc]\))/Copyright \\(co/mg;
561 # Convert some standard paragraph names.
562 if (s/^($PAT_OPTIONS): *\n+//o)
564 $sect = _('OPTIONS');
567 if (s/^($PAT_ENVIRONMENT): *\n+//o)
569 $sect = _('ENVIRONMENT');
572 if (s/^($PAT_FILES): *\n+//o)
577 elsif (s/^($PAT_EXAMPLES): *\n+//o)
579 $sect = _('EXAMPLES');
583 # Custom section indicated by a line containing "*Section Name*".
584 if (s/^\*(\w(.*\w)?)\* *\n+//)
587 $sect =~ tr/*/ /; # also accept *Section*Name*
588 push @sections, $sect;
595 $sect = _('COPYRIGHT');
598 # Bug reporting section.
599 elsif (/^($PAT_BUGS) /o)
601 $sect = _('REPORTING BUGS');
605 elsif (/^($PAT_AUTHOR)/o)
610 # Examples, indicated by an indented leading $, % or > are
611 # rendered in a constant width font.
612 if (/^( +)([\$\%>] )\S/)
617 while (s/^$indent\Q$prefix\E(\S.*)\n*//)
619 $include{$sect} .= "$break\n\\f(CW$prefix$1\\fR\n";
628 # Sub-sections have a trailing colon and the second line indented.
629 if (s/^(\S.*:) *\n / /)
631 $matched .= $& if %append_match;
632 $include{$sect} .= qq(.SS "$1"\n);
638 # Option with description.
639 if (s/^( {1,10}([+-]\S.*?))(?:( +(?!-))|\n( {20,}))(\S.*)\n//)
641 $matched .= $& if %append_match;
642 $indent = length ($4 || "$1$3");
643 $content = ".TP\n\x84$2\n\x84$5\n";
646 # Indent may be different on second line.
647 $indent = length $& if /^ {20,}/;
651 # Option without description.
652 elsif (s/^ {1,10}([+-]\S.*)\n//)
654 $matched .= $& if %append_match;
655 $content = ".HP\n\x84$1\n";
656 $indent = 80; # not continued
659 # Indented paragraph with tag.
660 elsif (s/^( +(\S.*?))(?:( +)|\n( {20,}))(\S.*)\n//)
662 $matched .= $& if %append_match;
663 $indent = length ($4 || "$1$3");
664 $content = ".TP\n\x84$2\n\x84$5\n";
667 # Indented paragraph.
668 elsif (s/^( +)(\S.*)\n//)
670 $matched .= $& if %append_match;
672 $content = ".IP\n\x84$2\n";
675 # Left justified paragraph.
679 $matched .= $& if %append_match;
680 $content = ".PP\n" if $include{$sect};
684 # Append continuations.
685 while ($indent ? s/^ {$indent}(\S.*)\n// : s/^(\S.*)\n//)
687 $matched .= $& if %append_match;
688 $content .= "\x84$1\n";
691 # Move to next paragraph.
696 # Leading dot and apostrophe protection.
701 # Examples should be verbatim.
702 unless ($sect eq _('EXAMPLES'))
705 s/(^|[ (])(-[][\w=-]+)/$1 . convert_option $2/mge;
707 # Italicise filenames: /a/b, $VAR/c/d, ~/e/f
709 (^|[ (]) # space/punctuation before
711 (?:\$\w+|~)? # leading variable, or tilde
712 (?:/\w(?:[\w.-]*\w)?)+ # path components
714 ($|[ ,;.)]) # space/punctuation after
717 $_ = fix_italic_spacing $_;
720 # Escape remaining hyphens.
723 if ($sect eq _('COPYRIGHT'))
725 # Insert line breaks before additional copyright messages
726 # and the disclaimer.
727 s/\n(Copyright |$PAT_FREE_SOFTWARE)/\n.br\n$1/og;
729 elsif ($sect eq _('REPORTING BUGS'))
731 # Handle multi-line bug reporting sections of the form:
733 # Report <program> bugs to <addr>
734 # GNU <package> home page: <url>
736 s/\n([[:upper:]])/\n.br\n$1/g;
740 # Check if matched paragraph contains /pat/.
743 for my $pat (keys %append_match)
745 if ($matched =~ $pat)
747 $content .= ".PP\n" unless $append_match{$pat} =~ /^\./;
748 $content .= $append_match{$pat};
753 $include{$sect} .= $content;
756 # Refer to the real documentation.
757 unless ($opt_no_info)
759 my $info_page = $opt_info || $program;
761 $sect = _('SEE ALSO');
762 $include{$sect} .= ".PP\n" if $include{$sect};
763 $include{$sect} .= sprintf _(<<'EOT'), $program, $program, $info_page;
764 The full documentation for
766 is maintained as a Texinfo manual. If the
770 programs are properly installed at your site, the command
774 should give you access to the complete manual.
778 # Append additional text.
779 while (my ($sect, $text) = each %append)
781 $include{$sect} .= $append{$sect};
785 while (my ($sect, $text) = each %replace)
787 $include{$sect} = $replace{$sect};
792 .\\" DO NOT MODIFY THIS FILE! It was generated by $this_program $this_version.
793 .TH $PROGRAM "$section" "$date" "$source" "$manual"
797 my @pre = (_('NAME'), _('SYNOPSIS'), _('DESCRIPTION'), _('OPTIONS'));
798 my @post = (_('ENVIRONMENT'), _('FILES'), _('EXAMPLES'), _('AUTHOR'),
799 _('REPORTING BUGS'), _('COPYRIGHT'), _('SEE ALSO'));
800 my %filter = map { $_ => 1 } @pre, @post;
804 for my $sect (@pre, (grep !$filter{$_}, @sections), @post)
806 next if $done{$sect}++; # ignore duplicates
807 next unless $include{$sect};
810 my $quote = $sect =~ /\W/ ? '"' : '';
811 print enc ".SH $quote$sect$quote\n";
813 for ($include{$sect})
815 # Replace leading dot, apostrophe, backslash and hyphen
822 # Convert some latin1 chars to troff equivalents
823 s/\xa0/\\ /g; # non-breaking space
830 close STDOUT or kark N_("%s: error writing to %s (%s)"), $this_program,
831 $opt_output || 'stdout', $!;
835 # Get program basename, and strip libtool "lt-" prefix if required.
840 s/^lt-// if $opt_libtool;
844 # Call program with given option and return results.
847 my ($prog, $opt) = @_;
848 my $stderr = $discard_stderr ? '/dev/null' : '&1';
850 map { s/ +$//; expand $_ }
852 `$prog $opt 2>$stderr`;
856 my $err = N_("%s: can't get `%s' info from %s%s");
857 my $extra = $discard_stderr
858 ? "\n" . N_("Try `--no-discard-stderr' if option outputs to stderr")
861 kark $err, $this_program, $opt, $prog, $extra;
867 # Convert option dashes to \- to stop nroff from hyphenating 'em, and
868 # embolden. Option arguments get italicised.
871 local $_ = '\fB' . shift;
874 unless (s/\[=(.*)\]$/\\fR[=\\fI$1\\fR]/)
884 # Insert spacing escape characters \, and \/ before and after italic text. See
885 # http://www.gnu.org/software/groff/manual/html_node/Ligatures-and-Kerning.html
886 sub fix_italic_spacing
889 s!\\fI(.*?)\\f([BRP])!\\fI\\,$1\\/\\f$2!g;
894 # Rename output and fix permissions
895 unless ($opts{stdout})
898 rename $tmp, $target or die "$0: can't rename $tmp to $target ($!)\n";
899 chmod 0555, $target or warn "$0: can't change mode of $target ($!)\n";