1#!/usr/bin/perl -w 2 3# Generate a short man page from --help and --version output. 4# Copyright (C) 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2009, 5# 2010, 2011, 2012, 2013, 2014, 2015 Free Software Foundation, Inc. 6 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) 10# any later version. 11 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. 16 17# You should have received a copy of the GNU General Public License 18# along with this program; if not, see <https://www.gnu.org/licenses/>. 19 20# Written by Brendan O'Dea <bod@debian.org> 21# Available from https://ftp.gnu.org/gnu/help2man/ 22 23use 5.008; 24use strict; 25use Getopt::Long; 26use Text::ParseWords qw(shellwords); 27use Text::Tabs qw(expand); 28use POSIX qw(strftime setlocale LC_ALL); 29 30my $this_program = 'help2man'; 31my $this_version = '1.47.3'; 32 33sub _ { $_[0] } 34sub configure_locale 35{ 36 my $locale = shift; 37 die "$this_program: no locale support (Locale::gettext required)\n" 38 unless $locale eq 'C'; 39} 40 41sub dec { $_[0] } 42sub enc { $_[0] } 43sub enc_user { $_[0] } 44sub kark { die +(sprintf shift, @_), "\n" } 45sub N_ { $_[0] } 46 47sub program_basename; 48sub get_option_value; 49sub convert_option; 50sub fix_italic_spacing; 51 52my $version_info = enc_user sprintf _(<<'EOT'), $this_program, $this_version; 53GNU %s %s 54 55Copyright (C) 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2009, 2010, 562011, 2012, 2013, 2014, 2015 Free Software Foundation, Inc. 57This is free software; see the source for copying conditions. There is NO 58warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 59 60Written by Brendan O'Dea <bod@debian.org> 61EOT 62 63my $help_info = enc_user sprintf _(<<'EOT'), $this_program, $this_program; 64`%s' generates a man page out of `--help' and `--version' output. 65 66Usage: %s [OPTION]... EXECUTABLE 67 68 -n, --name=STRING description for the NAME paragraph 69 -s, --section=SECTION section number for manual page (1, 6, 8) 70 -m, --manual=TEXT name of manual (User Commands, ...) 71 -S, --source=TEXT source of program (FSF, Debian, ...) 72 -L, --locale=STRING select locale (default "C") 73 -i, --include=FILE include material from `FILE' 74 -I, --opt-include=FILE include material from `FILE' if it exists 75 -o, --output=FILE send output to `FILE' 76 -p, --info-page=TEXT name of Texinfo manual 77 -N, --no-info suppress pointer to Texinfo manual 78 -l, --libtool exclude the `lt-' from the program name 79 --help print this help, then exit 80 --version print version number, then exit 81 82EXECUTABLE should accept `--help' and `--version' options and produce output on 83stdout although alternatives may be specified using: 84 85 -h, --help-option=STRING help option string 86 -v, --version-option=STRING version option string 87 --version-string=STRING version string 88 --no-discard-stderr include stderr when parsing option output 89 90Report bugs to <bug-help2man@gnu.org>. 91EOT 92 93my $section = 1; 94my $manual = ''; 95my $source = ''; 96my $help_option = '--help'; 97my $version_option = '--version'; 98my $discard_stderr = 1; 99my ($opt_name, @opt_include, $opt_output, $opt_info, $opt_no_info, $opt_libtool, 100 $version_text); 101 102my %opt_def = ( 103 'n|name=s' => \$opt_name, 104 's|section=s' => \$section, 105 'm|manual=s' => \$manual, 106 'S|source=s' => \$source, 107 'L|locale=s' => sub { configure_locale pop }, 108 'i|include=s' => sub { push @opt_include, [ pop, 1 ] }, 109 'I|opt-include=s' => sub { push @opt_include, [ pop, 0 ] }, 110 'o|output=s' => \$opt_output, 111 'p|info-page=s' => \$opt_info, 112 'N|no-info' => \$opt_no_info, 113 'l|libtool' => \$opt_libtool, 114 'help' => sub { print $help_info; exit }, 115 'version' => sub { print $version_info; exit }, 116 'h|help-option=s' => \$help_option, 117 'v|version-option=s' => \$version_option, 118 'version-string=s' => \$version_text, 119 'discard-stderr!' => \$discard_stderr, 120); 121 122# Parse options. 123Getopt::Long::config('bundling'); 124die $help_info unless GetOptions %opt_def and @ARGV == 1; 125 126my %include = (); 127my %replace = (); 128my %append = (); 129my %append_match = (); 130my @sections = (); # retain order of include file or in-line *section*s 131 132# Process include file (if given). Format is: 133# 134# Optional initial text, ignored. May include lines starting with `-' 135# which are processed as options. 136# 137# [section] 138# Verbatim text to be included in the named section. By default at 139# the start, but in the case of `name' and `synopsis' the content 140# will replace the autogenerated contents. 141# 142# [<section] 143# Verbatim text to be inserted at the start of the named section. 144# 145# [=section] 146# Verbatim text to replace the named section. 147# 148# [>section] 149# Verbatim text to be appended to the end of the named section. 150# 151# /pattern/ 152# Verbatim text for inclusion below a paragraph matching `pattern'. 153# 154 155while (@opt_include) 156{ 157 my ($inc, $required) = @{shift @opt_include}; 158 159 next unless -f $inc or $required; 160 kark N_("%s: can't open `%s' (%s)"), $this_program, $inc, $! 161 unless open INC, $inc; 162 163 my $key; 164 my $hash; 165 166 while (<INC>) 167 { 168 # Convert input to internal Perl format, so that multibyte 169 # sequences are treated as single characters. 170 $_ = dec $_; 171 172 # [section] 173 if (/^\[([^]]+)\]\s*$/) 174 { 175 $key = uc $1; 176 $key =~ s/^\s+//; 177 $key =~ s/\s+$//; 178 $hash = \%include; 179 # Handle explicit [<section], [=section] and [>section] 180 if ($key =~ s/^([<>=])\s*//) 181 { 182 if ($1 eq '>') { $hash = \%append; } 183 elsif ($1 eq '=') { $hash = \%replace; } 184 } 185 # NAME/SYNOPSIS replace by default 186 elsif ($key eq _('NAME') or $key eq _('SYNOPSIS')) 187 { 188 $hash = \%replace; 189 } 190 else 191 { 192 $hash = \%include; 193 } 194 195 push @sections, $key; 196 next; 197 } 198 199 # /pattern/ 200 if (m!^/(.*)/([ims]*)\s*$!) 201 { 202 my $pat = $2 ? "(?$2)$1" : $1; 203 204 # Check pattern. 205 eval { $key = qr($pat) }; 206 if ($@) 207 { 208 $@ =~ s/ at .*? line \d.*//; 209 die "$inc:$.:$@"; 210 } 211 212 $hash = \%append_match; 213 next; 214 } 215 216 # Check for options before the first section--anything else is 217 # silently ignored, allowing the first for comments and 218 # revision info. 219 unless ($key) 220 { 221 # handle options 222 if (/^-/) 223 { 224 local @ARGV = shellwords $_; 225 GetOptions %opt_def; 226 } 227 228 next; 229 } 230 231 $hash->{$key} .= $_; 232 } 233 234 close INC; 235 236 kark N_("%s: no valid information found in `%s'"), $this_program, $inc 237 unless $key; 238} 239 240# Compress trailing blank lines. 241for my $hash (\(%include, %replace, %append, %append_match)) 242{ 243 for (keys %$hash) { $hash->{$_} =~ s/\n+$/\n/ } 244} 245 246# Grab help and version info from executable. 247my $help_text = get_option_value $ARGV[0], $help_option; 248$version_text ||= get_option_value $ARGV[0], $version_option; 249 250# By default the generated manual pages will include the current date. This may 251# however be overriden by setting the environment variable $SOURCE_DATE_EPOCH 252# to an integer value of the seconds since the UNIX epoch. This is primarily 253# intended to support reproducible builds (wiki.debian.org/ReproducibleBuilds) 254# and will additionally ensure that the output date string is UTC. 255my $epoch_secs = time; 256if (exists $ENV{SOURCE_DATE_EPOCH} and $ENV{SOURCE_DATE_EPOCH} =~ /^(\d+)$/) 257{ 258 $epoch_secs = $1; 259 $ENV{TZ} = 'UTC0'; 260} 261 262# Translators: the following message is a strftime(3) format string, which in 263# the English version expands to the month as a word and the full year. It 264# is used on the footer of the generated manual pages. If in doubt, you may 265# just use %x as the value (which should be the full locale-specific date). 266my $date = enc strftime _("%B %Y"), localtime $epoch_secs; 267my $program = program_basename $ARGV[0]; 268my $package = $program; 269my $version; 270 271if ($opt_output) 272{ 273 unlink $opt_output or kark N_("%s: can't unlink %s (%s)"), 274 $this_program, $opt_output, $! if -e $opt_output; 275 276 open STDOUT, ">$opt_output" 277 or kark N_("%s: can't create %s (%s)"), $this_program, $opt_output, $!; 278} 279 280# The first line of the --version information is assumed to be in one 281# of the following formats: 282# 283# <version> 284# <program> <version> 285# {GNU,Free} <program> <version> 286# <program> ({GNU,Free} <package>) <version> 287# <program> - {GNU,Free} <package> <version> 288# 289# and separated from any copyright/author details by a blank line. 290 291($_, $version_text) = ((split /\n+/, $version_text, 2), ''); 292 293if (/^(\S+) +\(((?:GNU|Free) +[^)]+)\) +(.*)/ or 294 /^(\S+) +- *((?:GNU|Free) +\S+) +(.*)/) 295{ 296 $program = program_basename $1; 297 $package = $2; 298 $version = $3; 299} 300elsif (/^((?:GNU|Free) +)?(\S+) +(.*)/) 301{ 302 $program = program_basename $2; 303 $package = $1 ? "$1$program" : $program; 304 $version = $3; 305} 306else 307{ 308 $version = $_; 309} 310 311# No info for `info' itself. 312$opt_no_info = 1 if $program eq 'info'; 313 314if ($opt_name) 315{ 316 # --name overrides --include contents. 317 $replace{_('NAME')} = "$program \\- $opt_name\n"; 318} 319 320# Translators: "NAME", "SYNOPSIS" and other one or two word strings in all 321# upper case are manual page section headings. The man(1) manual page in your 322# language, if available should provide the conventional translations. 323for ($replace{_('NAME')} || ($include{_('NAME')} ||= '')) 324{ 325 if ($_) # Use first name given as $program 326 { 327 $program = $1 if /^([^\s,]+)(?:,?\s*[^\s,\\-]+)*\s+\\?-/; 328 } 329 else # Set a default (useless) NAME paragraph. 330 { 331 $_ = sprintf _("%s \\- manual page for %s %s") . "\n", $program, 332 $program, $version; 333 } 334} 335 336# Man pages traditionally have the page title in caps. 337my $PROGRAM = uc $program; 338 339# Set default page head/footers 340$source ||= "$program $version"; 341unless ($manual) 342{ 343 for ($section) 344 { 345 if (/^(1[Mm]|8)/) { $manual = enc _('System Administration Utilities') } 346 elsif (/^6/) { $manual = enc _('Games') } 347 else { $manual = enc _('User Commands') } 348 } 349} 350 351# Extract usage clause(s) [if any] for SYNOPSIS. 352# Translators: "Usage" and "or" here are patterns (regular expressions) which 353# are used to match the usage synopsis in program output. An example from cp 354# (GNU coreutils) which contains both strings: 355# Usage: cp [OPTION]... [-T] SOURCE DEST 356# or: cp [OPTION]... SOURCE... DIRECTORY 357# or: cp [OPTION]... -t DIRECTORY SOURCE... 358my $PAT_USAGE = _('Usage'); 359my $PAT_USAGE_CONT = _('or'); 360if ($help_text =~ s/^($PAT_USAGE):( +(\S+))(.*)((?:\n(?: {6}\1| *($PAT_USAGE_CONT): +\S).*)*)//om) 361{ 362 my @syn = $3 . $4; 363 364 if ($_ = $5) 365 { 366 s/^\n//; 367 for (split /\n/) { s/^ *(($PAT_USAGE_CONT): +)?//o; push @syn, $_ } 368 } 369 370 my $synopsis = ''; 371 for (@syn) 372 { 373 $synopsis .= ".br\n" if $synopsis; 374 s!^\S*/!!; 375 s/^lt-// if $opt_libtool; 376 s/^(\S+) *//; 377 $synopsis .= ".B $1\n"; 378 s/\s+$//; 379 s/(([][]|\.\.+)+)/\\fR$1\\fI/g; 380 s/^/\\fI/ unless s/^\\fR//; 381 $_ .= '\fR'; 382 s/(\\fI)( *)/$2$1/g; 383 s/\\fI\\fR//g; 384 s/^\\fR//; 385 s/\\fI$//; 386 s/^\./\\&./; 387 388 $_ = fix_italic_spacing $_; 389 $synopsis .= "$_\n"; 390 } 391 392 $include{_('SYNOPSIS')} .= $synopsis; 393} 394 395# Process text, initial section is DESCRIPTION. 396my $sect = _('DESCRIPTION'); 397$_ = "$help_text\n\n$version_text"; 398 399# Normalise paragraph breaks. 400s/^\n+//; 401s/\n*$/\n/; 402s/\n\n+/\n\n/g; 403 404# Join hyphenated lines. 405s/([A-Za-z])-\n *([A-Za-z])/$1$2/g; 406 407# Temporarily exchange leading dots, apostrophes and backslashes for 408# tokens. 409s/^\./\x80/mg; 410s/^'/\x81/mg; 411s/\\/\x82/g; 412 413# Translators: patterns are used to match common program output. In the source 414# these strings are all of the form of "my $PAT_something = _('...');" and are 415# regular expressions. If there is more than one commonly used string, you 416# may separate alternatives with "|". Spaces in these expressions are written 417# as " +" to indicate that more than one space may be matched. The string 418# "(?:[\\w-]+ +)?" in the bug reporting pattern is used to indicate an 419# optional word, so that either "Report bugs" or "Report _program_ bugs" will 420# be matched. 421my $PAT_BUGS = _('Report +(?:[\w-]+ +)?bugs|' . 422 'Email +bug +reports +to|' . 423 '.* +online +help:'); 424my $PAT_AUTHOR = _('Written +by'); 425my $PAT_OPTIONS = _('Options'); 426my $PAT_ENVIRONMENT = _('Environment'); 427my $PAT_FILES = _('Files'); 428my $PAT_EXAMPLES = _('Examples'); 429my $PAT_FREE_SOFTWARE = _('This +is +free +software'); 430my $PAT_SEE_ALSO = _('Full +documentation'); 431 432# Start a new paragraph (if required) for these. 433s/([^\n])\n($PAT_BUGS|$PAT_AUTHOR|$PAT_SEE_ALSO) /$1\n\n$2 /og; 434 435# Convert iso-8859-1 copyright symbol or (c) to nroff 436# character. 437s/^Copyright +(?:\xa9|\([Cc]\))/Copyright \\(co/mg; 438 439while (length) 440{ 441 # Convert some standard paragraph names. 442 if (s/^($PAT_OPTIONS): *\n+//o) 443 { 444 $sect = _('OPTIONS'); 445 next; 446 } 447 if (s/^($PAT_ENVIRONMENT): *\n+//o) 448 { 449 $sect = _('ENVIRONMENT'); 450 next; 451 } 452 if (s/^($PAT_FILES): *\n+//o) 453 { 454 $sect = _('FILES'); 455 next; 456 } 457 elsif (s/^($PAT_EXAMPLES): *\n+//o) 458 { 459 $sect = _('EXAMPLES'); 460 next; 461 } 462 463 # Custom section indicated by a line containing "*Section Name*". 464 if (s/^\*(\w(.*\w)?)\* *\n+//) 465 { 466 $sect = uc $1; 467 $sect =~ tr/*/ /; # also accept *Section*Name* 468 push @sections, $sect; 469 next; 470 } 471 472 # Copyright section. 473 if (/^Copyright /) 474 { 475 $sect = _('COPYRIGHT'); 476 } 477 478 # Bug reporting section. 479 elsif (/^($PAT_BUGS) /o) 480 { 481 $sect = _('REPORTING BUGS'); 482 } 483 484 # Author section. 485 elsif (/^($PAT_AUTHOR)/o) 486 { 487 $sect = _('AUTHOR'); 488 } 489 490 elsif (/^($PAT_SEE_ALSO)/o) 491 { 492 $sect = _('SEE ALSO'); 493 $opt_no_info = 1; 494 } 495 496 # Examples, indicated by an indented leading $, % or > are 497 # rendered in a constant width font. 498 if (/^( +)([\$\%>] )\S/) 499 { 500 my $indent = $1; 501 my $prefix = $2; 502 my $break = '.IP'; 503 while (s/^$indent\Q$prefix\E(\S.*)\n*//) 504 { 505 $include{$sect} .= "$break\n\\f(CW$prefix$1\\fR\n"; 506 $break = '.br'; 507 } 508 509 next; 510 } 511 512 my $matched = ''; 513 514 # Sub-sections have a trailing colon and the second line indented. 515 if (s/^(\S.*:) *\n / /) 516 { 517 $matched .= $& if %append_match; 518 $include{$sect} .= qq(.SS "$1"\n); 519 } 520 521 my $indent = 0; 522 my $content = ''; 523 524 # Option with description. 525 if (s/^( {1,10}([+-]\S.*?))(?:( +(?!-))|\n( {20,}))(\S.*)\n//) 526 { 527 $matched .= $& if %append_match; 528 $indent = length ($4 || "$1$3"); 529 $content = ".TP\n\x84$2\n\x84$5\n"; 530 unless ($4) 531 { 532 # Indent may be different on second line. 533 $indent = length $& if /^ {20,}/; 534 } 535 } 536 537 # Option without description. 538 elsif (s/^ {1,10}([+-]\S.*)\n//) 539 { 540 $matched .= $& if %append_match; 541 $content = ".HP\n\x84$1\n"; 542 $indent = 80; # not continued 543 } 544 545 # Indented paragraph with tag. 546 elsif (s/^( +(\S.*?) +)(\S.*)\n//) 547 { 548 $matched .= $& if %append_match; 549 $indent = length $1; 550 $content = ".TP\n\x84$2\n\x84$3\n"; 551 } 552 553 # Indented paragraph. 554 elsif (s/^( +)(\S.*)\n//) 555 { 556 $matched .= $& if %append_match; 557 $indent = length $1; 558 $content = ".IP\n\x84$2\n"; 559 } 560 561 # Left justified paragraph. 562 else 563 { 564 s/(.*)\n//; 565 $matched .= $& if %append_match; 566 $content = ".PP\n" if $include{$sect}; 567 $content .= "$1\n"; 568 } 569 570 # Append continuations. 571 while ($indent ? s/^ {$indent}(\S.*)\n// : s/^(\S.*)\n//) 572 { 573 $matched .= $& if %append_match; 574 $content .= "\x84$1\n"; 575 } 576 577 # Move to next paragraph. 578 s/^\n+//; 579 580 for ($content) 581 { 582 # Leading dot and apostrophe protection. 583 s/\x84\./\x80/g; 584 s/\x84'/\x81/g; 585 s/\x84//g; 586 587 # Examples should be verbatim. 588 unless ($sect eq _('EXAMPLES')) 589 { 590 # Convert options. 591 s/(^|[ (])(-[][\w=-]+)/$1 . convert_option $2/mge; 592 593 # Italicise filenames: /a/b, $VAR/c/d, ~/e/f 594 s! 595 (^|[ (]) # space/punctuation before 596 ( 597 (?:\$\w+|~)? # leading variable, or tilde 598 (?:/\w(?:[\w.-]*\w)?)+ # path components 599 ) 600 ($|[ ,;.)]) # space/punctuation after 601 !$1\\fI$2\\fP$3!xmg; 602 603 $_ = fix_italic_spacing $_; 604 } 605 606 # Escape remaining hyphens. 607 s/-/\x83/g; 608 609 if ($sect eq _('COPYRIGHT')) 610 { 611 # Insert line breaks before additional copyright messages 612 # and the disclaimer. 613 s/\n(Copyright |$PAT_FREE_SOFTWARE)/\n.br\n$1/og; 614 } 615 elsif ($sect eq _('REPORTING BUGS')) 616 { 617 # Handle multi-line bug reporting sections of the form: 618 # 619 # Report <program> bugs to <addr> 620 # GNU <package> home page: <url> 621 # ... 622 s/\n([[:upper:]])/\n.br\n$1/g; 623 } 624 elsif ($sect eq _('SEE ALSO')) 625 { 626 # Handle external references of the form: 627 # 628 # GNU <package> online resources: <addr> 629 # Full documentation at: <addr> 630 # or available locally via: info ... 631 # 632 s/\'/\\(aq/g; # shell quotes for info command 633 s/\n(.)/\n.br\n$1/g; # separate lines for each item 634 } 635 } 636 637 # Check if matched paragraph contains /pat/. 638 if (%append_match) 639 { 640 for my $pat (keys %append_match) 641 { 642 if ($matched =~ $pat) 643 { 644 $content .= ".PP\n" unless $append_match{$pat} =~ /^\./; 645 $content .= $append_match{$pat}; 646 } 647 } 648 } 649 650 $include{$sect} .= $content; 651} 652 653# Refer to the real documentation. 654unless ($opt_no_info) 655{ 656 my $info_page = $opt_info || $program; 657 658 $sect = _('SEE ALSO'); 659 $include{$sect} .= ".PP\n" if $include{$sect}; 660 $include{$sect} .= sprintf _(<<'EOT'), $program, $program, $info_page; 661The full documentation for 662.B %s 663is maintained as a Texinfo manual. If the 664.B info 665and 666.B %s 667programs are properly installed at your site, the command 668.IP 669.B info %s 670.PP 671should give you access to the complete manual. 672EOT 673} 674 675# Append additional text. 676while (my ($sect, $text) = each %append) 677{ 678 $include{$sect} .= $append{$sect}; 679} 680 681# Replace sections. 682while (my ($sect, $text) = each %replace) 683{ 684 $include{$sect} = $replace{$sect}; 685} 686 687# Output header. 688print <<EOT; 689.\\" DO NOT MODIFY THIS FILE! It was generated by $this_program $this_version. 690.TH $PROGRAM "$section" "$date" "$source" "$manual" 691EOT 692 693# Section ordering. 694my @pre = (_('NAME'), _('SYNOPSIS'), _('DESCRIPTION'), _('OPTIONS'), 695 _('EXAMPLES')); 696my @post = (_('ENVIRONMENT'), _('FILES'), _('AUTHOR'), 697 _('REPORTING BUGS'), _('COPYRIGHT'), _('SEE ALSO')); 698my %filter = map { $_ => 1 } @pre, @post; 699 700# Output content. 701my %done; 702for my $sect (@pre, (grep !$filter{$_}, @sections), @post) 703{ 704 next if $done{$sect}++; # ignore duplicates 705 next unless $include{$sect}; 706 if ($include{$sect}) 707 { 708 my $quote = $sect =~ /\W/ ? '"' : ''; 709 print enc ".SH $quote$sect$quote\n"; 710 711 for ($include{$sect}) 712 { 713 # Replace leading dot, apostrophe, backslash and hyphen 714 # tokens. 715 s/\x80/\\&./g; 716 s/\x81/\\&'/g; 717 s/\x82/\\e/g; 718 s/\x83/\\-/g; 719 720 # Convert some latin1 chars to troff equivalents 721 s/\xa0/\\ /g; # non-breaking space 722 723 print enc $_; 724 } 725 } 726} 727 728close STDOUT or kark N_("%s: error writing to %s (%s)"), $this_program, 729 $opt_output || 'stdout', $!; 730 731exit; 732 733# Get program basename, and strip libtool "lt-" prefix if required. 734sub program_basename 735{ 736 local $_ = shift; 737 s!.*/!!; 738 s/^lt-// if $opt_libtool; 739 $_; 740} 741 742# Call program with given option and return results. 743sub get_option_value 744{ 745 my ($prog, $opt) = @_; 746 my $stderr = $discard_stderr ? '/dev/null' : '&1'; 747 my $value = join '', 748 map { s/ +$//; expand $_ } 749 map { dec $_ } 750 `$prog $opt 2>$stderr`; 751 752 unless ($value) 753 { 754 my $err = N_("%s: can't get `%s' info from %s%s"); 755 my $extra = $discard_stderr 756 ? "\n" . N_("Try `--no-discard-stderr' if option outputs to stderr") 757 : ''; 758 759 kark $err, $this_program, $opt, $prog, $extra; 760 } 761 762 $value; 763} 764 765# Convert option dashes to \- to stop nroff from hyphenating 'em, and 766# embolden. Option arguments get italicised. 767sub convert_option 768{ 769 local $_ = '\fB' . shift; 770 771 s/-/\x83/g; 772 unless (s/\[=(.*)\]$/\\fR[=\\fI$1\\fR]/) 773 { 774 s/=(.)/\\fR=\\fI$1/; 775 s/ (.)/ \\fI$1/; 776 $_ .= '\fR'; 777 } 778 779 $_; 780} 781 782# Insert spacing escape characters \, and \/ before and after italic text. See 783# https://www.gnu.org/software/groff/manual/html_node/Ligatures-and-Kerning.html 784sub fix_italic_spacing 785{ 786 local $_ = shift; 787 s!\\fI(.*?)\\f([BRP])!\\fI\\,$1\\/\\f$2!g; 788 return $_; 789} 790