1*946379e7Schristos#!/usr/bin/perl -w 2*946379e7Schristos 3*946379e7Schristos# Generate a short man page from --help and --version output. 4*946379e7Schristos# Copyright � 1997, 1998, 1999, 2000 Free Software Foundation, Inc. 5*946379e7Schristos 6*946379e7Schristos# This program is free software; you can redistribute it and/or modify 7*946379e7Schristos# it under the terms of the GNU General Public License as published by 8*946379e7Schristos# the Free Software Foundation; either version 2, or (at your option) 9*946379e7Schristos# any later version. 10*946379e7Schristos 11*946379e7Schristos# This program is distributed in the hope that it will be useful, 12*946379e7Schristos# but WITHOUT ANY WARRANTY; without even the implied warranty of 13*946379e7Schristos# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14*946379e7Schristos# GNU General Public License for more details. 15*946379e7Schristos 16*946379e7Schristos# You should have received a copy of the GNU General Public License 17*946379e7Schristos# along with this program; if not, write to the Free Software Foundation, 18*946379e7Schristos# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 19*946379e7Schristos 20*946379e7Schristos# Written by Brendan O'Dea <bod@compusol.com.au> 21*946379e7Schristos# Available from ftp://ftp.gnu.org/gnu/help2man/ 22*946379e7Schristos 23*946379e7Schristosuse 5.004; 24*946379e7Schristosuse strict; 25*946379e7Schristosuse Getopt::Long; 26*946379e7Schristosuse Text::Tabs qw(expand); 27*946379e7Schristosuse POSIX qw(strftime setlocale LC_TIME); 28*946379e7Schristos 29*946379e7Schristosmy $this_program = 'help2man'; 30*946379e7Schristosmy $this_version = '1.24'; 31*946379e7Schristosmy $version_info = <<EOT; 32*946379e7SchristosGNU $this_program $this_version 33*946379e7Schristos 34*946379e7SchristosCopyright (C) 1997, 1998, 1999, 2000 Free Software Foundation, Inc. 35*946379e7SchristosThis is free software; see the source for copying conditions. There is NO 36*946379e7Schristoswarranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 37*946379e7Schristos 38*946379e7SchristosWritten by Brendan O'Dea <bod\@compusol.com.au> 39*946379e7SchristosEOT 40*946379e7Schristos 41*946379e7Schristosmy $help_info = <<EOT; 42*946379e7Schristos`$this_program' generates a man page out of `--help' and `--version' output. 43*946379e7Schristos 44*946379e7SchristosUsage: $this_program [OPTION]... EXECUTABLE 45*946379e7Schristos 46*946379e7Schristos -n, --name=STRING use `STRING' as the description for the NAME paragraph 47*946379e7Schristos -s, --section=SECTION use `SECTION' as the section for the man page 48*946379e7Schristos -i, --include=FILE include material from `FILE' 49*946379e7Schristos -I, --opt-include=FILE include material from `FILE' if it exists 50*946379e7Schristos -o, --output=FILE send output to `FILE' 51*946379e7Schristos -N, --no-info suppress pointer to Texinfo manual 52*946379e7Schristos --help print this help, then exit 53*946379e7Schristos --version print version number, then exit 54*946379e7Schristos 55*946379e7SchristosEXECUTABLE should accept `--help' and `--version' options. 56*946379e7Schristos 57*946379e7SchristosReport bugs to <bug-help2man\@gnu.org>. 58*946379e7SchristosEOT 59*946379e7Schristos 60*946379e7Schristosmy $section = 1; 61*946379e7Schristosmy ($opt_name, @opt_include, $opt_output, $opt_no_info); 62*946379e7Schristosmy %opt_def = ( 63*946379e7Schristos 'n|name=s' => \$opt_name, 64*946379e7Schristos 's|section=s' => \$section, 65*946379e7Schristos 'i|include=s' => sub { push @opt_include, [ pop, 1 ] }, 66*946379e7Schristos 'I|opt-include=s' => sub { push @opt_include, [ pop, 0 ] }, 67*946379e7Schristos 'o|output=s' => \$opt_output, 68*946379e7Schristos 'N|no-info' => \$opt_no_info, 69*946379e7Schristos); 70*946379e7Schristos 71*946379e7Schristos# Parse options. 72*946379e7SchristosGetopt::Long::config('bundling'); 73*946379e7SchristosGetOptions (%opt_def, 74*946379e7Schristos help => sub { print $help_info; exit }, 75*946379e7Schristos version => sub { print $version_info; exit }, 76*946379e7Schristos) or die $help_info; 77*946379e7Schristos 78*946379e7Schristosdie $help_info unless @ARGV == 1; 79*946379e7Schristos 80*946379e7Schristosmy %include = (); 81*946379e7Schristosmy %append = (); 82*946379e7Schristosmy @include = (); # retain order given in include file 83*946379e7Schristos 84*946379e7Schristos# Provide replacement `quote-regex' operator for pre-5.005. 85*946379e7SchristosBEGIN { eval q(sub qr { '' =~ $_[0]; $_[0] }) if $] < 5.005 } 86*946379e7Schristos 87*946379e7Schristos# Process include file (if given). Format is: 88*946379e7Schristos# 89*946379e7Schristos# [section name] 90*946379e7Schristos# verbatim text 91*946379e7Schristos# 92*946379e7Schristos# or 93*946379e7Schristos# 94*946379e7Schristos# /pattern/ 95*946379e7Schristos# verbatim text 96*946379e7Schristos# 97*946379e7Schristos 98*946379e7Schristoswhile (@opt_include) 99*946379e7Schristos{ 100*946379e7Schristos my ($inc, $required) = @{shift @opt_include}; 101*946379e7Schristos 102*946379e7Schristos next unless -f $inc or $required; 103*946379e7Schristos die "$this_program: can't open `$inc' ($!)\n" 104*946379e7Schristos unless open INC, $inc; 105*946379e7Schristos 106*946379e7Schristos my $key; 107*946379e7Schristos my $hash = \%include; 108*946379e7Schristos 109*946379e7Schristos while (<INC>) 110*946379e7Schristos { 111*946379e7Schristos # [section] 112*946379e7Schristos if (/^\[([^]]+)\]/) 113*946379e7Schristos { 114*946379e7Schristos $key = uc $1; 115*946379e7Schristos $key =~ s/^\s+//; 116*946379e7Schristos $key =~ s/\s+$//; 117*946379e7Schristos $hash = \%include; 118*946379e7Schristos push @include, $key unless $include{$key}; 119*946379e7Schristos next; 120*946379e7Schristos } 121*946379e7Schristos 122*946379e7Schristos # /pattern/ 123*946379e7Schristos if (m!^/(.*)/([ims]*)!) 124*946379e7Schristos { 125*946379e7Schristos my $pat = $2 ? "(?$2)$1" : $1; 126*946379e7Schristos 127*946379e7Schristos # Check pattern. 128*946379e7Schristos eval { $key = qr($pat) }; 129*946379e7Schristos if ($@) 130*946379e7Schristos { 131*946379e7Schristos $@ =~ s/ at .*? line \d.*//; 132*946379e7Schristos die "$inc:$.:$@"; 133*946379e7Schristos } 134*946379e7Schristos 135*946379e7Schristos $hash = \%append; 136*946379e7Schristos next; 137*946379e7Schristos } 138*946379e7Schristos 139*946379e7Schristos # Check for options before the first section--anything else is 140*946379e7Schristos # silently ignored, allowing the first for comments and 141*946379e7Schristos # revision info. 142*946379e7Schristos unless ($key) 143*946379e7Schristos { 144*946379e7Schristos # handle options 145*946379e7Schristos if (/^-/) 146*946379e7Schristos { 147*946379e7Schristos local @ARGV = split; 148*946379e7Schristos GetOptions %opt_def; 149*946379e7Schristos } 150*946379e7Schristos 151*946379e7Schristos next; 152*946379e7Schristos } 153*946379e7Schristos 154*946379e7Schristos $hash->{$key} ||= ''; 155*946379e7Schristos $hash->{$key} .= $_; 156*946379e7Schristos } 157*946379e7Schristos 158*946379e7Schristos close INC; 159*946379e7Schristos 160*946379e7Schristos die "$this_program: no valid information found in `$inc'\n" 161*946379e7Schristos unless $key; 162*946379e7Schristos} 163*946379e7Schristos 164*946379e7Schristos# Compress trailing blank lines. 165*946379e7Schristosfor my $hash (\(%include, %append)) 166*946379e7Schristos{ 167*946379e7Schristos for (keys %$hash) { $hash->{$_} =~ s/\n+$/\n/ } 168*946379e7Schristos} 169*946379e7Schristos 170*946379e7Schristos# Turn off localisation of executable's ouput. 171*946379e7Schristos@ENV{qw(LANGUAGE LANG LC_ALL)} = ('C') x 3; 172*946379e7Schristos 173*946379e7Schristos# Turn off localisation of date (for strftime). 174*946379e7Schristossetlocale LC_TIME, 'C'; 175*946379e7Schristos 176*946379e7Schristos# Grab help and version info from executable. 177*946379e7Schristosmy ($help_text, $version_text) = map { 178*946379e7Schristos join '', map { s/ +$//; expand $_ } `$ARGV[0] --$_ 2>/dev/null` 179*946379e7Schristos or die "$this_program: can't get `--$_' info from $ARGV[0]\n" 180*946379e7Schristos} qw(help version); 181*946379e7Schristos 182*946379e7Schristosmy $date = strftime "%B %Y", localtime; 183*946379e7Schristos(my $program = $ARGV[0]) =~ s!.*/!!; 184*946379e7Schristosmy $package = $program; 185*946379e7Schristosmy $version; 186*946379e7Schristos 187*946379e7Schristosif ($opt_output) 188*946379e7Schristos{ 189*946379e7Schristos unlink $opt_output 190*946379e7Schristos or die "$this_program: can't unlink $opt_output ($!)\n" 191*946379e7Schristos if -e $opt_output; 192*946379e7Schristos 193*946379e7Schristos open STDOUT, ">$opt_output" 194*946379e7Schristos or die "$this_program: can't create $opt_output ($!)\n"; 195*946379e7Schristos} 196*946379e7Schristos 197*946379e7Schristos# The first line of the --version information is assumed to be in one 198*946379e7Schristos# of the following formats: 199*946379e7Schristos# 200*946379e7Schristos# <version> 201*946379e7Schristos# <program> <version> 202*946379e7Schristos# {GNU,Free} <program> <version> 203*946379e7Schristos# <program> ({GNU,Free} <package>) <version> 204*946379e7Schristos# <program> - {GNU,Free} <package> <version> 205*946379e7Schristos# 206*946379e7Schristos# and seperated from any copyright/author details by a blank line. 207*946379e7Schristos 208*946379e7Schristos($_, $version_text) = split /\n+/, $version_text, 2; 209*946379e7Schristos 210*946379e7Schristosif (/^(\S+) +\(((?:GNU|Free) +[^)]+)\) +(.*)/ or 211*946379e7Schristos /^(\S+) +- *((?:GNU|Free) +\S+) +(.*)/) 212*946379e7Schristos{ 213*946379e7Schristos $program = $1; 214*946379e7Schristos $package = $2; 215*946379e7Schristos $version = $3; 216*946379e7Schristos} 217*946379e7Schristoselsif (/^((?:GNU|Free) +)?(\S+) +(.*)/) 218*946379e7Schristos{ 219*946379e7Schristos $program = $2; 220*946379e7Schristos $package = $1 ? "$1$2" : $2; 221*946379e7Schristos $version = $3; 222*946379e7Schristos} 223*946379e7Schristoselse 224*946379e7Schristos{ 225*946379e7Schristos $version = $_; 226*946379e7Schristos} 227*946379e7Schristos 228*946379e7Schristos$program =~ s!.*/!!; 229*946379e7Schristos 230*946379e7Schristos# No info for `info' itself. 231*946379e7Schristos$opt_no_info = 1 if $program eq 'info'; 232*946379e7Schristos 233*946379e7Schristos# --name overrides --include contents. 234*946379e7Schristos$include{NAME} = "$program \\- $opt_name\n" if $opt_name; 235*946379e7Schristos 236*946379e7Schristos# Default (useless) NAME paragraph. 237*946379e7Schristos$include{NAME} ||= "$program \\- manual page for $program $version\n"; 238*946379e7Schristos 239*946379e7Schristos# Man pages traditionally have the page title in caps. 240*946379e7Schristosmy $PROGRAM = uc $program; 241*946379e7Schristos 242*946379e7Schristos# Extract usage clause(s) [if any] for SYNOPSIS. 243*946379e7Schristosif ($help_text =~ s/^Usage:( +(\S+))(.*)((?:\n(?: {6}\1| *or: +\S).*)*)//m) 244*946379e7Schristos{ 245*946379e7Schristos my @syn = $2 . $3; 246*946379e7Schristos 247*946379e7Schristos if ($_ = $4) 248*946379e7Schristos { 249*946379e7Schristos s/^\n//; 250*946379e7Schristos for (split /\n/) { s/^ *(or: +)?//; push @syn, $_ } 251*946379e7Schristos } 252*946379e7Schristos 253*946379e7Schristos my $synopsis = ''; 254*946379e7Schristos for (@syn) 255*946379e7Schristos { 256*946379e7Schristos $synopsis .= ".br\n" if $synopsis; 257*946379e7Schristos s!^\S*/!!; 258*946379e7Schristos s/^(\S+) *//; 259*946379e7Schristos $synopsis .= ".B $1\n"; 260*946379e7Schristos s/\s+$//; 261*946379e7Schristos s/(([][]|\.\.+)+)/\\fR$1\\fI/g; 262*946379e7Schristos s/^/\\fI/ unless s/^\\fR//; 263*946379e7Schristos $_ .= '\fR'; 264*946379e7Schristos s/(\\fI)( *)/$2$1/g; 265*946379e7Schristos s/\\fI\\fR//g; 266*946379e7Schristos s/^\\fR//; 267*946379e7Schristos s/\\fI$//; 268*946379e7Schristos s/^\./\\&./; 269*946379e7Schristos 270*946379e7Schristos $synopsis .= "$_\n"; 271*946379e7Schristos } 272*946379e7Schristos 273*946379e7Schristos $include{SYNOPSIS} ||= $synopsis; 274*946379e7Schristos} 275*946379e7Schristos 276*946379e7Schristos# Process text, initial section is DESCRIPTION. 277*946379e7Schristosmy $sect = 'DESCRIPTION'; 278*946379e7Schristos$_ = "$help_text\n\n$version_text"; 279*946379e7Schristos 280*946379e7Schristos# Normalise paragraph breaks. 281*946379e7Schristoss/^\n+//; 282*946379e7Schristoss/\n*$/\n/; 283*946379e7Schristoss/\n\n+/\n\n/g; 284*946379e7Schristos 285*946379e7Schristos# Temporarily exchange leading dots, apostrophes and backslashes for 286*946379e7Schristos# tokens. 287*946379e7Schristoss/^\./\x80/mg; 288*946379e7Schristoss/^'/\x81/mg; 289*946379e7Schristoss/\\/\x82/g; 290*946379e7Schristos 291*946379e7Schristos# Start a new paragraph (if required) for these. 292*946379e7Schristoss/([^\n])\n(Report +bugs|Email +bug +reports +to|Written +by)/$1\n\n$2/g; 293*946379e7Schristos 294*946379e7Schristossub convert_option; 295*946379e7Schristos 296*946379e7Schristoswhile (length) 297*946379e7Schristos{ 298*946379e7Schristos # Convert some standard paragraph names. 299*946379e7Schristos if (s/^(Options|Examples): *\n//) 300*946379e7Schristos { 301*946379e7Schristos $sect = uc $1; 302*946379e7Schristos next; 303*946379e7Schristos } 304*946379e7Schristos 305*946379e7Schristos # Copyright section 306*946379e7Schristos if (/^Copyright +[(\xa9]/) 307*946379e7Schristos { 308*946379e7Schristos $sect = 'COPYRIGHT'; 309*946379e7Schristos $include{$sect} ||= ''; 310*946379e7Schristos $include{$sect} .= ".PP\n" if $include{$sect}; 311*946379e7Schristos 312*946379e7Schristos my $copy; 313*946379e7Schristos ($copy, $_) = split /\n\n/, $_, 2; 314*946379e7Schristos 315*946379e7Schristos for ($copy) 316*946379e7Schristos { 317*946379e7Schristos # Add back newline 318*946379e7Schristos s/\n*$/\n/; 319*946379e7Schristos 320*946379e7Schristos # Convert iso9959-1 copyright symbol or (c) to nroff 321*946379e7Schristos # character. 322*946379e7Schristos s/^Copyright +(?:\xa9|\([Cc]\))/Copyright \\(co/mg; 323*946379e7Schristos 324*946379e7Schristos # Insert line breaks before additional copyright messages 325*946379e7Schristos # and the disclaimer. 326*946379e7Schristos s/(.)\n(Copyright |This +is +free +software)/$1\n.br\n$2/g; 327*946379e7Schristos 328*946379e7Schristos # Join hyphenated lines. 329*946379e7Schristos s/([A-Za-z])-\n */$1/g; 330*946379e7Schristos } 331*946379e7Schristos 332*946379e7Schristos $include{$sect} .= $copy; 333*946379e7Schristos $_ ||= ''; 334*946379e7Schristos next; 335*946379e7Schristos } 336*946379e7Schristos 337*946379e7Schristos # Catch bug report text. 338*946379e7Schristos if (/^(Report +bugs|Email +bug +reports +to) /) 339*946379e7Schristos { 340*946379e7Schristos $sect = 'REPORTING BUGS'; 341*946379e7Schristos } 342*946379e7Schristos 343*946379e7Schristos # Author section. 344*946379e7Schristos elsif (/^Written +by/) 345*946379e7Schristos { 346*946379e7Schristos $sect = 'AUTHOR'; 347*946379e7Schristos } 348*946379e7Schristos 349*946379e7Schristos # Examples, indicated by an indented leading $, % or > are 350*946379e7Schristos # rendered in a constant width font. 351*946379e7Schristos if (/^( +)([\$\%>] )\S/) 352*946379e7Schristos { 353*946379e7Schristos my $indent = $1; 354*946379e7Schristos my $prefix = $2; 355*946379e7Schristos my $break = '.IP'; 356*946379e7Schristos $include{$sect} ||= ''; 357*946379e7Schristos while (s/^$indent\Q$prefix\E(\S.*)\n*//) 358*946379e7Schristos { 359*946379e7Schristos $include{$sect} .= "$break\n\\f(CW$prefix$1\\fR\n"; 360*946379e7Schristos $break = '.br'; 361*946379e7Schristos } 362*946379e7Schristos 363*946379e7Schristos next; 364*946379e7Schristos } 365*946379e7Schristos 366*946379e7Schristos my $matched = ''; 367*946379e7Schristos $include{$sect} ||= ''; 368*946379e7Schristos 369*946379e7Schristos # Sub-sections have a trailing colon and the second line indented. 370*946379e7Schristos if (s/^(\S.*:) *\n / /) 371*946379e7Schristos { 372*946379e7Schristos $matched .= $& if %append; 373*946379e7Schristos $include{$sect} .= qq(.SS "$1"\n); 374*946379e7Schristos } 375*946379e7Schristos 376*946379e7Schristos my $indent = 0; 377*946379e7Schristos my $content = ''; 378*946379e7Schristos 379*946379e7Schristos # Option with description. 380*946379e7Schristos if (s/^( {1,10}([+-]\S.*?))(?:( +)|\n( {20,}))(\S.*)\n//) 381*946379e7Schristos { 382*946379e7Schristos $matched .= $& if %append; 383*946379e7Schristos $indent = length ($4 || "$1$3"); 384*946379e7Schristos $content = ".TP\n\x83$2\n\x83$5\n"; 385*946379e7Schristos unless ($4) 386*946379e7Schristos { 387*946379e7Schristos # Indent may be different on second line. 388*946379e7Schristos $indent = length $& if /^ {20,}/; 389*946379e7Schristos } 390*946379e7Schristos } 391*946379e7Schristos 392*946379e7Schristos # Option without description. 393*946379e7Schristos elsif (s/^ {1,10}([+-]\S.*)\n//) 394*946379e7Schristos { 395*946379e7Schristos $matched .= $& if %append; 396*946379e7Schristos $content = ".HP\n\x83$1\n"; 397*946379e7Schristos $indent = 80; # not continued 398*946379e7Schristos } 399*946379e7Schristos 400*946379e7Schristos # Indented paragraph with tag. 401*946379e7Schristos elsif (s/^( +(\S.*?) +)(\S.*)\n//) 402*946379e7Schristos { 403*946379e7Schristos $matched .= $& if %append; 404*946379e7Schristos $indent = length $1; 405*946379e7Schristos $content = ".TP\n\x83$2\n\x83$3\n"; 406*946379e7Schristos } 407*946379e7Schristos 408*946379e7Schristos # Indented paragraph. 409*946379e7Schristos elsif (s/^( +)(\S.*)\n//) 410*946379e7Schristos { 411*946379e7Schristos $matched .= $& if %append; 412*946379e7Schristos $indent = length $1; 413*946379e7Schristos $content = ".IP\n\x83$2\n"; 414*946379e7Schristos } 415*946379e7Schristos 416*946379e7Schristos # Left justified paragraph. 417*946379e7Schristos else 418*946379e7Schristos { 419*946379e7Schristos s/(.*)\n//; 420*946379e7Schristos $matched .= $& if %append; 421*946379e7Schristos $content = ".PP\n" if $include{$sect}; 422*946379e7Schristos $content .= "$1\n"; 423*946379e7Schristos } 424*946379e7Schristos 425*946379e7Schristos # Append continuations. 426*946379e7Schristos while (s/^ {$indent}(\S.*)\n//) 427*946379e7Schristos { 428*946379e7Schristos $matched .= $& if %append; 429*946379e7Schristos $content .= "\x83$1\n" 430*946379e7Schristos } 431*946379e7Schristos 432*946379e7Schristos # Move to next paragraph. 433*946379e7Schristos s/^\n+//; 434*946379e7Schristos 435*946379e7Schristos for ($content) 436*946379e7Schristos { 437*946379e7Schristos # Leading dot and apostrophe protection. 438*946379e7Schristos s/\x83\./\x80/g; 439*946379e7Schristos s/\x83'/\x81/g; 440*946379e7Schristos s/\x83//g; 441*946379e7Schristos 442*946379e7Schristos # Convert options. 443*946379e7Schristos s/(^| )(-[][\w=-]+)/$1 . convert_option $2/mge; 444*946379e7Schristos } 445*946379e7Schristos 446*946379e7Schristos # Check if matched paragraph contains /pat/. 447*946379e7Schristos if (%append) 448*946379e7Schristos { 449*946379e7Schristos for my $pat (keys %append) 450*946379e7Schristos { 451*946379e7Schristos if ($matched =~ $pat) 452*946379e7Schristos { 453*946379e7Schristos $content .= ".PP\n" unless $append{$pat} =~ /^\./; 454*946379e7Schristos $content .= $append{$pat}; 455*946379e7Schristos } 456*946379e7Schristos } 457*946379e7Schristos } 458*946379e7Schristos 459*946379e7Schristos $include{$sect} .= $content; 460*946379e7Schristos} 461*946379e7Schristos 462*946379e7Schristos# Refer to the real documentation. 463*946379e7Schristosunless ($opt_no_info) 464*946379e7Schristos{ 465*946379e7Schristos $sect = 'SEE ALSO'; 466*946379e7Schristos $include{$sect} ||= ''; 467*946379e7Schristos $include{$sect} .= ".PP\n" if $include{$sect}; 468*946379e7Schristos $include{$sect} .= <<EOT; 469*946379e7SchristosThe full documentation for 470*946379e7Schristos.B $program 471*946379e7Schristosis maintained as a Texinfo manual. If the 472*946379e7Schristos.B info 473*946379e7Schristosand 474*946379e7Schristos.B $program 475*946379e7Schristosprograms are properly installed at your site, the command 476*946379e7Schristos.IP 477*946379e7Schristos.B info $program 478*946379e7Schristos.PP 479*946379e7Schristosshould give you access to the complete manual. 480*946379e7SchristosEOT 481*946379e7Schristos} 482*946379e7Schristos 483*946379e7Schristos# Output header. 484*946379e7Schristosprint <<EOT; 485*946379e7Schristos.\\" DO NOT MODIFY THIS FILE! It was generated by $this_program $this_version. 486*946379e7Schristos.TH $PROGRAM "$section" "$date" "$package $version" GNU 487*946379e7SchristosEOT 488*946379e7Schristos 489*946379e7Schristos# Section ordering. 490*946379e7Schristosmy @pre = qw(NAME SYNOPSIS DESCRIPTION OPTIONS EXAMPLES); 491*946379e7Schristosmy @post = ('AUTHOR', 'REPORTING BUGS', 'COPYRIGHT', 'SEE ALSO'); 492*946379e7Schristosmy $filter = join '|', @pre, @post; 493*946379e7Schristos 494*946379e7Schristos# Output content. 495*946379e7Schristosfor (@pre, (grep ! /^($filter)$/o, @include), @post) 496*946379e7Schristos{ 497*946379e7Schristos if ($include{$_}) 498*946379e7Schristos { 499*946379e7Schristos my $quote = /\W/ ? '"' : ''; 500*946379e7Schristos print ".SH $quote$_$quote\n"; 501*946379e7Schristos 502*946379e7Schristos for ($include{$_}) 503*946379e7Schristos { 504*946379e7Schristos # Replace leading dot, apostrophe and backslash tokens. 505*946379e7Schristos s/\x80/\\&./g; 506*946379e7Schristos s/\x81/\\&'/g; 507*946379e7Schristos s/\x82/\\e/g; 508*946379e7Schristos print; 509*946379e7Schristos } 510*946379e7Schristos } 511*946379e7Schristos} 512*946379e7Schristos 513*946379e7Schristosexit; 514*946379e7Schristos 515*946379e7Schristos# Convert option dashes to \- to stop nroff from hyphenating 'em, and 516*946379e7Schristos# embolden. Option arguments get italicised. 517*946379e7Schristossub convert_option 518*946379e7Schristos{ 519*946379e7Schristos local $_ = '\fB' . shift; 520*946379e7Schristos 521*946379e7Schristos s/-/\\-/g; 522*946379e7Schristos unless (s/\[=(.*)\]$/\\fR[=\\fI$1\\fR]/) 523*946379e7Schristos { 524*946379e7Schristos s/=(.)/\\fR=\\fI$1/; 525*946379e7Schristos s/ (.)/ \\fI$1/; 526*946379e7Schristos $_ .= '\fR'; 527*946379e7Schristos } 528*946379e7Schristos 529*946379e7Schristos $_; 530*946379e7Schristos} 531