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