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