17c478bd9Sstevel@tonic-gate#!/usr/bin/perl -w
27c478bd9Sstevel@tonic-gate
37c478bd9Sstevel@tonic-gate# Generate a short man page from --help and --version output.
47c478bd9Sstevel@tonic-gate# Copyright � 1997, 1998, 1999, 2000 Free Software Foundation, Inc.
57c478bd9Sstevel@tonic-gate
67c478bd9Sstevel@tonic-gate# This program is free software; you can redistribute it and/or modify
77c478bd9Sstevel@tonic-gate# it under the terms of the GNU General Public License as published by
87c478bd9Sstevel@tonic-gate# the Free Software Foundation; either version 2, or (at your option)
97c478bd9Sstevel@tonic-gate# any later version.
107c478bd9Sstevel@tonic-gate
117c478bd9Sstevel@tonic-gate# This program is distributed in the hope that it will be useful,
127c478bd9Sstevel@tonic-gate# but WITHOUT ANY WARRANTY; without even the implied warranty of
137c478bd9Sstevel@tonic-gate# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
147c478bd9Sstevel@tonic-gate# GNU General Public License for more details.
157c478bd9Sstevel@tonic-gate
167c478bd9Sstevel@tonic-gate# You should have received a copy of the GNU General Public License
177c478bd9Sstevel@tonic-gate# along with this program; if not, write to the Free Software Foundation,
187c478bd9Sstevel@tonic-gate# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
197c478bd9Sstevel@tonic-gate
207c478bd9Sstevel@tonic-gate# Written by Brendan O'Dea <bod@compusol.com.au>
217c478bd9Sstevel@tonic-gate# Available from ftp://ftp.gnu.org/gnu/help2man/
227c478bd9Sstevel@tonic-gate
237c478bd9Sstevel@tonic-gateuse 5.004;
247c478bd9Sstevel@tonic-gateuse strict;
257c478bd9Sstevel@tonic-gateuse Getopt::Long;
267c478bd9Sstevel@tonic-gateuse Text::Tabs qw(expand);
277c478bd9Sstevel@tonic-gateuse POSIX qw(strftime setlocale LC_TIME);
287c478bd9Sstevel@tonic-gate
297c478bd9Sstevel@tonic-gatemy $this_program = 'help2man';
307c478bd9Sstevel@tonic-gatemy $this_version = '1.23';
317c478bd9Sstevel@tonic-gatemy $version_info = <<EOT;
327c478bd9Sstevel@tonic-gateGNU $this_program $this_version
337c478bd9Sstevel@tonic-gate
347c478bd9Sstevel@tonic-gateCopyright (C) 1997, 1998, 1999, 2000 Free Software Foundation, Inc.
357c478bd9Sstevel@tonic-gateThis is free software; see the source for copying conditions.  There is NO
367c478bd9Sstevel@tonic-gatewarranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
377c478bd9Sstevel@tonic-gate
387c478bd9Sstevel@tonic-gateWritten by Brendan O'Dea <bod\@compusol.com.au>
397c478bd9Sstevel@tonic-gateEOT
407c478bd9Sstevel@tonic-gate
417c478bd9Sstevel@tonic-gatemy $help_info = <<EOT;
427c478bd9Sstevel@tonic-gate`$this_program' generates a man page out of `--help' and `--version' output.
437c478bd9Sstevel@tonic-gate
447c478bd9Sstevel@tonic-gateUsage: $this_program [OPTION]... EXECUTABLE
457c478bd9Sstevel@tonic-gate
467c478bd9Sstevel@tonic-gate -n, --name=STRING       use `STRING' as the description for the NAME paragraph
477c478bd9Sstevel@tonic-gate -s, --section=SECTION   use `SECTION' as the section for the man page
487c478bd9Sstevel@tonic-gate -i, --include=FILE      include material from `FILE'
497c478bd9Sstevel@tonic-gate -I, --opt-include=FILE  include material from `FILE' if it exists
507c478bd9Sstevel@tonic-gate -o, --output=FILE       send output to `FILE'
517c478bd9Sstevel@tonic-gate -N, --no-info           suppress pointer to Texinfo manual
527c478bd9Sstevel@tonic-gate     --help              print this help, then exit
537c478bd9Sstevel@tonic-gate     --version           print version number, then exit
547c478bd9Sstevel@tonic-gate
557c478bd9Sstevel@tonic-gateEXECUTABLE should accept `--help' and `--version' options.
567c478bd9Sstevel@tonic-gate
577c478bd9Sstevel@tonic-gateReport bugs to <bug-help2man\@gnu.org>.
587c478bd9Sstevel@tonic-gateEOT
597c478bd9Sstevel@tonic-gate
607c478bd9Sstevel@tonic-gatemy $section = 1;
617c478bd9Sstevel@tonic-gatemy ($opt_name, @opt_include, $opt_output, $opt_no_info);
627c478bd9Sstevel@tonic-gate
637c478bd9Sstevel@tonic-gate# Parse options.
647c478bd9Sstevel@tonic-gateGetopt::Long::config('bundling');
657c478bd9Sstevel@tonic-gateGetOptions (
667c478bd9Sstevel@tonic-gate    'n|name=s'		=> \$opt_name,
677c478bd9Sstevel@tonic-gate    's|section=s'	=> \$section,
687c478bd9Sstevel@tonic-gate    'i|include=s'	=> sub { push @opt_include, [ pop, 1 ] },
697c478bd9Sstevel@tonic-gate    'I|opt-include=s'	=> sub { push @opt_include, [ pop, 0 ] },
707c478bd9Sstevel@tonic-gate    'o|output=s'	=> \$opt_output,
717c478bd9Sstevel@tonic-gate    'N|no-info'		=> \$opt_no_info,
727c478bd9Sstevel@tonic-gate    help		=> sub { print $help_info; exit },
737c478bd9Sstevel@tonic-gate    version		=> sub { print $version_info; exit },
747c478bd9Sstevel@tonic-gate) or die $help_info;
757c478bd9Sstevel@tonic-gate
767c478bd9Sstevel@tonic-gatedie $help_info unless @ARGV == 1;
777c478bd9Sstevel@tonic-gate
787c478bd9Sstevel@tonic-gatemy %include = ();
797c478bd9Sstevel@tonic-gatemy %append = ();
807c478bd9Sstevel@tonic-gatemy @include = (); # retain order given in include file
817c478bd9Sstevel@tonic-gate
827c478bd9Sstevel@tonic-gate# Provide replacement `quote-regex' operator for pre-5.005.
837c478bd9Sstevel@tonic-gateBEGIN { eval q(sub qr { '' =~ $_[0]; $_[0] }) if $] < 5.005 }
847c478bd9Sstevel@tonic-gate
857c478bd9Sstevel@tonic-gate# Process include file (if given).  Format is:
867c478bd9Sstevel@tonic-gate#
877c478bd9Sstevel@tonic-gate#   [section name]
887c478bd9Sstevel@tonic-gate#   verbatim text
897c478bd9Sstevel@tonic-gate#
907c478bd9Sstevel@tonic-gate# or
917c478bd9Sstevel@tonic-gate#
927c478bd9Sstevel@tonic-gate#   /pattern/
937c478bd9Sstevel@tonic-gate#   verbatim text
947c478bd9Sstevel@tonic-gate#
957c478bd9Sstevel@tonic-gate
967c478bd9Sstevel@tonic-gatefor (@opt_include)
977c478bd9Sstevel@tonic-gate{
987c478bd9Sstevel@tonic-gate    my ($inc, $required) = @$_;
997c478bd9Sstevel@tonic-gate
1007c478bd9Sstevel@tonic-gate    next unless -f $inc or $required;
1017c478bd9Sstevel@tonic-gate    die "$this_program: can't open `$inc' ($!)\n"
1027c478bd9Sstevel@tonic-gate	unless open INC, $inc;
1037c478bd9Sstevel@tonic-gate
1047c478bd9Sstevel@tonic-gate    my $key;
1057c478bd9Sstevel@tonic-gate    my $hash = \%include;
1067c478bd9Sstevel@tonic-gate
1077c478bd9Sstevel@tonic-gate    while (<INC>)
1087c478bd9Sstevel@tonic-gate    {
1097c478bd9Sstevel@tonic-gate	# [section]
1107c478bd9Sstevel@tonic-gate	if (/^\[([^]]+)\]/)
1117c478bd9Sstevel@tonic-gate	{
1127c478bd9Sstevel@tonic-gate	    $key = uc $1;
1137c478bd9Sstevel@tonic-gate	    $key =~ s/^\s+//;
1147c478bd9Sstevel@tonic-gate	    $key =~ s/\s+$//;
1157c478bd9Sstevel@tonic-gate	    $hash = \%include;
1167c478bd9Sstevel@tonic-gate	    push @include, $key unless $include{$key};
1177c478bd9Sstevel@tonic-gate	    next;
1187c478bd9Sstevel@tonic-gate	}
1197c478bd9Sstevel@tonic-gate
1207c478bd9Sstevel@tonic-gate	# /pattern/
1217c478bd9Sstevel@tonic-gate	if (m!^/(.*)/([ims]*)!)
1227c478bd9Sstevel@tonic-gate	{
1237c478bd9Sstevel@tonic-gate	    my $pat = $2 ? "(?$2)$1" : $1;
1247c478bd9Sstevel@tonic-gate
1257c478bd9Sstevel@tonic-gate	    # Check pattern.
1267c478bd9Sstevel@tonic-gate	    eval { $key = qr($pat) };
1277c478bd9Sstevel@tonic-gate	    if ($@)
1287c478bd9Sstevel@tonic-gate	    {
1297c478bd9Sstevel@tonic-gate		$@ =~ s/ at .*? line \d.*//;
1307c478bd9Sstevel@tonic-gate		die "$inc:$.:$@";
1317c478bd9Sstevel@tonic-gate	    }
1327c478bd9Sstevel@tonic-gate
1337c478bd9Sstevel@tonic-gate	    $hash = \%append;
1347c478bd9Sstevel@tonic-gate	    next;
1357c478bd9Sstevel@tonic-gate	}
1367c478bd9Sstevel@tonic-gate
1377c478bd9Sstevel@tonic-gate	# Silently ignore anything before the first
1387c478bd9Sstevel@tonic-gate	# section--allows for comments and revision info.
1397c478bd9Sstevel@tonic-gate	next unless $key;
1407c478bd9Sstevel@tonic-gate
1417c478bd9Sstevel@tonic-gate	$hash->{$key} ||= '';
1427c478bd9Sstevel@tonic-gate	$hash->{$key} .= $_;
1437c478bd9Sstevel@tonic-gate    }
1447c478bd9Sstevel@tonic-gate
1457c478bd9Sstevel@tonic-gate    close INC;
1467c478bd9Sstevel@tonic-gate
1477c478bd9Sstevel@tonic-gate    die "$this_program: no valid information found in `$inc'\n"
1487c478bd9Sstevel@tonic-gate	unless $key;
1497c478bd9Sstevel@tonic-gate}
1507c478bd9Sstevel@tonic-gate
1517c478bd9Sstevel@tonic-gate# Compress trailing blank lines.
1527c478bd9Sstevel@tonic-gatefor my $hash (\(%include, %append))
1537c478bd9Sstevel@tonic-gate{
1547c478bd9Sstevel@tonic-gate    for (keys %$hash) { $hash->{$_} =~ s/\n+$/\n/ }
1557c478bd9Sstevel@tonic-gate}
1567c478bd9Sstevel@tonic-gate
1577c478bd9Sstevel@tonic-gate# Turn off localisation of executable's ouput.
1587c478bd9Sstevel@tonic-gate@ENV{qw(LANGUAGE LANG LC_ALL)} = ('C') x 3;
1597c478bd9Sstevel@tonic-gate
1607c478bd9Sstevel@tonic-gate# Turn off localisation of date (for strftime).
1617c478bd9Sstevel@tonic-gatesetlocale LC_TIME, 'C';
1627c478bd9Sstevel@tonic-gate
1637c478bd9Sstevel@tonic-gate# Grab help and version info from executable.
1647c478bd9Sstevel@tonic-gatemy ($help_text, $version_text) = map {
1657c478bd9Sstevel@tonic-gate    join '', map { s/ +$//; expand $_ } `$ARGV[0] --$_ 2>/dev/null`
1667c478bd9Sstevel@tonic-gate	or die "$this_program: can't get `--$_' info from $ARGV[0]\n"
1677c478bd9Sstevel@tonic-gate} qw(help version);
1687c478bd9Sstevel@tonic-gate
1697c478bd9Sstevel@tonic-gatemy $date = strftime "%B %Y", localtime;
1707c478bd9Sstevel@tonic-gate(my $program = $ARGV[0]) =~ s!.*/!!;
1717c478bd9Sstevel@tonic-gatemy $package = $program;
1727c478bd9Sstevel@tonic-gatemy $version;
1737c478bd9Sstevel@tonic-gate
1747c478bd9Sstevel@tonic-gateif ($opt_output)
1757c478bd9Sstevel@tonic-gate{
1767c478bd9Sstevel@tonic-gate    unlink $opt_output
1777c478bd9Sstevel@tonic-gate	or die "$this_program: can't unlink $opt_output ($!)\n"
1787c478bd9Sstevel@tonic-gate	if -e $opt_output;
1797c478bd9Sstevel@tonic-gate
1807c478bd9Sstevel@tonic-gate    open STDOUT, ">$opt_output"
1817c478bd9Sstevel@tonic-gate	or die "$this_program: can't create $opt_output ($!)\n";
1827c478bd9Sstevel@tonic-gate}
1837c478bd9Sstevel@tonic-gate
1847c478bd9Sstevel@tonic-gate# The first line of the --version information is assumed to be in one
1857c478bd9Sstevel@tonic-gate# of the following formats:
1867c478bd9Sstevel@tonic-gate#
1877c478bd9Sstevel@tonic-gate#   <version>
1887c478bd9Sstevel@tonic-gate#   <program> <version>
1897c478bd9Sstevel@tonic-gate#   {GNU,Free} <program> <version>
1907c478bd9Sstevel@tonic-gate#   <program> ({GNU,Free} <package>) <version>
1917c478bd9Sstevel@tonic-gate#   <program> - {GNU,Free} <package> <version>
1927c478bd9Sstevel@tonic-gate#
1937c478bd9Sstevel@tonic-gate# and seperated from any copyright/author details by a blank line.
1947c478bd9Sstevel@tonic-gate
1957c478bd9Sstevel@tonic-gate($_, $version_text) = split /\n+/, $version_text, 2;
1967c478bd9Sstevel@tonic-gate
1977c478bd9Sstevel@tonic-gateif (/^(\S+) +\(((?:GNU|Free) +[^)]+)\) +(.*)/ or
1987c478bd9Sstevel@tonic-gate    /^(\S+) +- *((?:GNU|Free) +\S+) +(.*)/)
1997c478bd9Sstevel@tonic-gate{
2007c478bd9Sstevel@tonic-gate    $program = $1;
2017c478bd9Sstevel@tonic-gate    $package = $2;
2027c478bd9Sstevel@tonic-gate    $version = $3;
2037c478bd9Sstevel@tonic-gate}
2047c478bd9Sstevel@tonic-gateelsif (/^((?:GNU|Free) +)?(\S+) +(.*)/)
2057c478bd9Sstevel@tonic-gate{
2067c478bd9Sstevel@tonic-gate    $program = $2;
2077c478bd9Sstevel@tonic-gate    $package = $1 ? "$1$2" : $2;
2087c478bd9Sstevel@tonic-gate    $version = $3;
2097c478bd9Sstevel@tonic-gate}
2107c478bd9Sstevel@tonic-gateelse
2117c478bd9Sstevel@tonic-gate{
2127c478bd9Sstevel@tonic-gate    $version = $_;
2137c478bd9Sstevel@tonic-gate}
2147c478bd9Sstevel@tonic-gate
2157c478bd9Sstevel@tonic-gate$program =~ s!.*/!!;
2167c478bd9Sstevel@tonic-gate
2177c478bd9Sstevel@tonic-gate# No info for `info' itself.
2187c478bd9Sstevel@tonic-gate$opt_no_info = 1 if $program eq 'info';
2197c478bd9Sstevel@tonic-gate
2207c478bd9Sstevel@tonic-gate# --name overrides --include contents.
2217c478bd9Sstevel@tonic-gate$include{NAME} = "$program \\- $opt_name\n" if $opt_name;
2227c478bd9Sstevel@tonic-gate
2237c478bd9Sstevel@tonic-gate# Default (useless) NAME paragraph.
2247c478bd9Sstevel@tonic-gate$include{NAME} ||= "$program \\- manual page for $program $version\n";
2257c478bd9Sstevel@tonic-gate
2267c478bd9Sstevel@tonic-gate# Man pages traditionally have the page title in caps.
2277c478bd9Sstevel@tonic-gatemy $PROGRAM = uc $program;
2287c478bd9Sstevel@tonic-gate
2297c478bd9Sstevel@tonic-gate# Extract usage clause(s) [if any] for SYNOPSIS.
2307c478bd9Sstevel@tonic-gateif ($help_text =~ s/^Usage:( +(\S+))(.*)((?:\n(?: {6}\1| *or: +\S).*)*)//m)
2317c478bd9Sstevel@tonic-gate{
2327c478bd9Sstevel@tonic-gate    my @syn = $2 . $3;
2337c478bd9Sstevel@tonic-gate
2347c478bd9Sstevel@tonic-gate    if ($_ = $4)
2357c478bd9Sstevel@tonic-gate    {
2367c478bd9Sstevel@tonic-gate	s/^\n//;
2377c478bd9Sstevel@tonic-gate	for (split /\n/) { s/^ *(or: +)?//; push @syn, $_ }
2387c478bd9Sstevel@tonic-gate    }
2397c478bd9Sstevel@tonic-gate
2407c478bd9Sstevel@tonic-gate    my $synopsis = '';
2417c478bd9Sstevel@tonic-gate    for (@syn)
2427c478bd9Sstevel@tonic-gate    {
2437c478bd9Sstevel@tonic-gate	$synopsis .= ".br\n" if $synopsis;
2447c478bd9Sstevel@tonic-gate	s!^\S*/!!;
2457c478bd9Sstevel@tonic-gate	s/^(\S+) *//;
2467c478bd9Sstevel@tonic-gate	$synopsis .= ".B $1\n";
2477c478bd9Sstevel@tonic-gate	s/\s+$//;
2487c478bd9Sstevel@tonic-gate	s/(([][]|\.\.+)+)/\\fR$1\\fI/g;
2497c478bd9Sstevel@tonic-gate	s/^/\\fI/ unless s/^\\fR//;
2507c478bd9Sstevel@tonic-gate	$_ .= '\fR';
2517c478bd9Sstevel@tonic-gate	s/(\\fI)( *)/$2$1/g;
2527c478bd9Sstevel@tonic-gate	s/\\fI\\fR//g;
2537c478bd9Sstevel@tonic-gate	s/^\\fR//;
2547c478bd9Sstevel@tonic-gate	s/\\fI$//;
2557c478bd9Sstevel@tonic-gate	s/^\./\\&./;
2567c478bd9Sstevel@tonic-gate
2577c478bd9Sstevel@tonic-gate	$synopsis .= "$_\n";
2587c478bd9Sstevel@tonic-gate    }
2597c478bd9Sstevel@tonic-gate
2607c478bd9Sstevel@tonic-gate    $include{SYNOPSIS} ||= $synopsis;
2617c478bd9Sstevel@tonic-gate}
2627c478bd9Sstevel@tonic-gate
2637c478bd9Sstevel@tonic-gate# Process text, initial section is DESCRIPTION.
2647c478bd9Sstevel@tonic-gatemy $sect = 'DESCRIPTION';
2657c478bd9Sstevel@tonic-gate$_ = "$help_text\n\n$version_text";
2667c478bd9Sstevel@tonic-gate
2677c478bd9Sstevel@tonic-gate# Normalise paragraph breaks.
2687c478bd9Sstevel@tonic-gates/^\n+//;
2697c478bd9Sstevel@tonic-gates/\n*$/\n/;
2707c478bd9Sstevel@tonic-gates/\n\n+/\n\n/g;
2717c478bd9Sstevel@tonic-gate
2727c478bd9Sstevel@tonic-gate# Temporarily exchange leading dots, apostrophes and backslashes for
2737c478bd9Sstevel@tonic-gate# tokens.
2747c478bd9Sstevel@tonic-gates/^\./\x80/mg;
2757c478bd9Sstevel@tonic-gates/^'/\x81/mg;
2767c478bd9Sstevel@tonic-gates/\\/\x82/g;
2777c478bd9Sstevel@tonic-gate
2787c478bd9Sstevel@tonic-gate# Start a new paragraph (if required) for these.
2797c478bd9Sstevel@tonic-gates/([^\n])\n(Report +bugs|Email +bug +reports +to|Written +by)/$1\n\n$2/g;
2807c478bd9Sstevel@tonic-gate
2817c478bd9Sstevel@tonic-gatesub convert_option;
2827c478bd9Sstevel@tonic-gate
2837c478bd9Sstevel@tonic-gatewhile (length)
2847c478bd9Sstevel@tonic-gate{
2857c478bd9Sstevel@tonic-gate    # Convert some standard paragraph names.
2867c478bd9Sstevel@tonic-gate    if (s/^(Options|Examples): *\n//)
2877c478bd9Sstevel@tonic-gate    {
2887c478bd9Sstevel@tonic-gate	$sect = uc $1;
2897c478bd9Sstevel@tonic-gate	next;
2907c478bd9Sstevel@tonic-gate    }
2917c478bd9Sstevel@tonic-gate
2927c478bd9Sstevel@tonic-gate    # Copyright section
2937c478bd9Sstevel@tonic-gate    if (/^Copyright +[(\xa9]/)
2947c478bd9Sstevel@tonic-gate    {
2957c478bd9Sstevel@tonic-gate	$sect = 'COPYRIGHT';
2967c478bd9Sstevel@tonic-gate	$include{$sect} ||= '';
2977c478bd9Sstevel@tonic-gate	$include{$sect} .= ".PP\n" if $include{$sect};
2987c478bd9Sstevel@tonic-gate
2997c478bd9Sstevel@tonic-gate	my $copy;
3007c478bd9Sstevel@tonic-gate	($copy, $_) = split /\n\n/, $_, 2;
3017c478bd9Sstevel@tonic-gate
3027c478bd9Sstevel@tonic-gate	for ($copy)
3037c478bd9Sstevel@tonic-gate	{
3047c478bd9Sstevel@tonic-gate	    # Add back newline
3057c478bd9Sstevel@tonic-gate	    s/\n*$/\n/;
3067c478bd9Sstevel@tonic-gate
3077c478bd9Sstevel@tonic-gate	    # Convert iso9959-1 copyright symbol or (c) to nroff
3087c478bd9Sstevel@tonic-gate	    # character.
3097c478bd9Sstevel@tonic-gate	    s/^Copyright +(?:\xa9|\([Cc]\))/Copyright \\(co/mg;
3107c478bd9Sstevel@tonic-gate
3117c478bd9Sstevel@tonic-gate	    # Insert line breaks before additional copyright messages
3127c478bd9Sstevel@tonic-gate	    # and the disclaimer.
3137c478bd9Sstevel@tonic-gate	    s/(.)\n(Copyright |This +is +free +software)/$1\n.br\n$2/g;
3147c478bd9Sstevel@tonic-gate
3157c478bd9Sstevel@tonic-gate	    # Join hyphenated lines.
3167c478bd9Sstevel@tonic-gate	    s/([A-Za-z])-\n */$1/g;
3177c478bd9Sstevel@tonic-gate	}
3187c478bd9Sstevel@tonic-gate
3197c478bd9Sstevel@tonic-gate	$include{$sect} .= $copy;
3207c478bd9Sstevel@tonic-gate	$_ ||= '';
3217c478bd9Sstevel@tonic-gate	next;
3227c478bd9Sstevel@tonic-gate    }
3237c478bd9Sstevel@tonic-gate
3247c478bd9Sstevel@tonic-gate    # Catch bug report text.
3257c478bd9Sstevel@tonic-gate    if (/^(Report +bugs|Email +bug +reports +to) /)
3267c478bd9Sstevel@tonic-gate    {
3277c478bd9Sstevel@tonic-gate	$sect = 'REPORTING BUGS';
3287c478bd9Sstevel@tonic-gate    }
3297c478bd9Sstevel@tonic-gate
3307c478bd9Sstevel@tonic-gate    # Author section.
3317c478bd9Sstevel@tonic-gate    elsif (/^Written +by/)
3327c478bd9Sstevel@tonic-gate    {
3337c478bd9Sstevel@tonic-gate	$sect = 'AUTHOR';
3347c478bd9Sstevel@tonic-gate    }
3357c478bd9Sstevel@tonic-gate
3367c478bd9Sstevel@tonic-gate    # Examples, indicated by an indented leading $, % or > are
3377c478bd9Sstevel@tonic-gate    # rendered in a constant width font.
3387c478bd9Sstevel@tonic-gate    if (/^( +)([\$\%>] )\S/)
3397c478bd9Sstevel@tonic-gate    {
3407c478bd9Sstevel@tonic-gate	my $indent = $1;
3417c478bd9Sstevel@tonic-gate	my $prefix = $2;
3427c478bd9Sstevel@tonic-gate	my $break = '.IP';
3437c478bd9Sstevel@tonic-gate	$include{$sect} ||= '';
3447c478bd9Sstevel@tonic-gate	while (s/^$indent\Q$prefix\E(\S.*)\n*//)
3457c478bd9Sstevel@tonic-gate	{
3467c478bd9Sstevel@tonic-gate	    $include{$sect} .= "$break\n\\f(CW$prefix$1\\fR\n";
3477c478bd9Sstevel@tonic-gate	    $break = '.br';
3487c478bd9Sstevel@tonic-gate	}
3497c478bd9Sstevel@tonic-gate
3507c478bd9Sstevel@tonic-gate	next;
3517c478bd9Sstevel@tonic-gate    }
3527c478bd9Sstevel@tonic-gate
3537c478bd9Sstevel@tonic-gate    my $matched = '';
3547c478bd9Sstevel@tonic-gate    $include{$sect} ||= '';
3557c478bd9Sstevel@tonic-gate
3567c478bd9Sstevel@tonic-gate    # Sub-sections have a trailing colon and the second line indented.
3577c478bd9Sstevel@tonic-gate    if (s/^(\S.*:) *\n / /)
3587c478bd9Sstevel@tonic-gate    {
3597c478bd9Sstevel@tonic-gate	$matched .= $& if %append;
3607c478bd9Sstevel@tonic-gate	$include{$sect} .= qq(.SS "$1"\n);
3617c478bd9Sstevel@tonic-gate    }
3627c478bd9Sstevel@tonic-gate
3637c478bd9Sstevel@tonic-gate    my $indent = 0;
3647c478bd9Sstevel@tonic-gate    my $content = '';
3657c478bd9Sstevel@tonic-gate
3667c478bd9Sstevel@tonic-gate    # Option with description.
3677c478bd9Sstevel@tonic-gate    if (s/^( {1,10}([+-]\S.*?))(?:(  +)|\n( {20,}))(\S.*)\n//)
3687c478bd9Sstevel@tonic-gate    {
3697c478bd9Sstevel@tonic-gate	$matched .= $& if %append;
3707c478bd9Sstevel@tonic-gate	$indent = length ($4 || "$1$3");
3717c478bd9Sstevel@tonic-gate	$content = ".TP\n\x83$2\n\x83$5\n";
3727c478bd9Sstevel@tonic-gate	unless ($4)
3737c478bd9Sstevel@tonic-gate	{
3747c478bd9Sstevel@tonic-gate	    # Indent may be different on second line.
3757c478bd9Sstevel@tonic-gate	    $indent = length $& if /^ {20,}/;
3767c478bd9Sstevel@tonic-gate	}
3777c478bd9Sstevel@tonic-gate    }
3787c478bd9Sstevel@tonic-gate
3797c478bd9Sstevel@tonic-gate    # Option without description.
3807c478bd9Sstevel@tonic-gate    elsif (s/^ {1,10}([+-]\S.*)\n//)
3817c478bd9Sstevel@tonic-gate    {
3827c478bd9Sstevel@tonic-gate	$matched .= $& if %append;
3837c478bd9Sstevel@tonic-gate	$content = ".HP\n\x83$1\n";
3847c478bd9Sstevel@tonic-gate	$indent = 80; # not continued
3857c478bd9Sstevel@tonic-gate    }
3867c478bd9Sstevel@tonic-gate
3877c478bd9Sstevel@tonic-gate    # Indented paragraph with tag.
3887c478bd9Sstevel@tonic-gate    elsif (s/^( +(\S.*?)  +)(\S.*)\n//)
3897c478bd9Sstevel@tonic-gate    {
3907c478bd9Sstevel@tonic-gate	$matched .= $& if %append;
3917c478bd9Sstevel@tonic-gate	$indent = length $1;
3927c478bd9Sstevel@tonic-gate	$content = ".TP\n\x83$2\n\x83$3\n";
3937c478bd9Sstevel@tonic-gate    }
3947c478bd9Sstevel@tonic-gate
3957c478bd9Sstevel@tonic-gate    # Indented paragraph.
3967c478bd9Sstevel@tonic-gate    elsif (s/^( +)(\S.*)\n//)
3977c478bd9Sstevel@tonic-gate    {
3987c478bd9Sstevel@tonic-gate	$matched .= $& if %append;
3997c478bd9Sstevel@tonic-gate	$indent = length $1;
4007c478bd9Sstevel@tonic-gate	$content = ".IP\n\x83$2\n";
4017c478bd9Sstevel@tonic-gate    }
4027c478bd9Sstevel@tonic-gate
4037c478bd9Sstevel@tonic-gate    # Left justified paragraph.
4047c478bd9Sstevel@tonic-gate    else
4057c478bd9Sstevel@tonic-gate    {
4067c478bd9Sstevel@tonic-gate	s/(.*)\n//;
4077c478bd9Sstevel@tonic-gate	$matched .= $& if %append;
4087c478bd9Sstevel@tonic-gate	$content = ".PP\n" if $include{$sect};
4097c478bd9Sstevel@tonic-gate	$content .= "$1\n";
4107c478bd9Sstevel@tonic-gate    }
4117c478bd9Sstevel@tonic-gate
4127c478bd9Sstevel@tonic-gate    # Append continuations.
4137c478bd9Sstevel@tonic-gate    while (s/^ {$indent}(\S.*)\n//)
4147c478bd9Sstevel@tonic-gate    {
4157c478bd9Sstevel@tonic-gate	$matched .= $& if %append;
4167c478bd9Sstevel@tonic-gate	$content .= "\x83$1\n"
4177c478bd9Sstevel@tonic-gate    }
4187c478bd9Sstevel@tonic-gate
4197c478bd9Sstevel@tonic-gate    # Move to next paragraph.
4207c478bd9Sstevel@tonic-gate    s/^\n+//;
4217c478bd9Sstevel@tonic-gate
4227c478bd9Sstevel@tonic-gate    for ($content)
4237c478bd9Sstevel@tonic-gate    {
4247c478bd9Sstevel@tonic-gate	# Leading dot and apostrophe protection.
4257c478bd9Sstevel@tonic-gate	s/\x83\./\x80/g;
4267c478bd9Sstevel@tonic-gate	s/\x83'/\x81/g;
4277c478bd9Sstevel@tonic-gate	s/\x83//g;
4287c478bd9Sstevel@tonic-gate
4297c478bd9Sstevel@tonic-gate	# Convert options.
4307c478bd9Sstevel@tonic-gate	s/(^| )(-[][\w=-]+)/$1 . convert_option $2/mge;
4317c478bd9Sstevel@tonic-gate    }
4327c478bd9Sstevel@tonic-gate
4337c478bd9Sstevel@tonic-gate    # Check if matched paragraph contains /pat/.
4347c478bd9Sstevel@tonic-gate    if (%append)
4357c478bd9Sstevel@tonic-gate    {
4367c478bd9Sstevel@tonic-gate	for my $pat (keys %append)
4377c478bd9Sstevel@tonic-gate	{
4387c478bd9Sstevel@tonic-gate	    if ($matched =~ $pat)
4397c478bd9Sstevel@tonic-gate	    {
4407c478bd9Sstevel@tonic-gate		$content .= ".PP\n" unless $append{$pat} =~ /^\./;
4417c478bd9Sstevel@tonic-gate		$content .= $append{$pat};
4427c478bd9Sstevel@tonic-gate	    }
4437c478bd9Sstevel@tonic-gate	}
4447c478bd9Sstevel@tonic-gate    }
4457c478bd9Sstevel@tonic-gate
4467c478bd9Sstevel@tonic-gate    $include{$sect} .= $content;
4477c478bd9Sstevel@tonic-gate}
4487c478bd9Sstevel@tonic-gate
4497c478bd9Sstevel@tonic-gate# Refer to the real documentation.
4507c478bd9Sstevel@tonic-gateunless ($opt_no_info)
4517c478bd9Sstevel@tonic-gate{
4527c478bd9Sstevel@tonic-gate    $sect = 'SEE ALSO';
4537c478bd9Sstevel@tonic-gate    $include{$sect} ||= '';
4547c478bd9Sstevel@tonic-gate    $include{$sect} .= ".PP\n" if $include{$sect};
4557c478bd9Sstevel@tonic-gate    $include{$sect} .= <<EOT;
4567c478bd9Sstevel@tonic-gateThe full documentation for
4577c478bd9Sstevel@tonic-gate.B $program
4587c478bd9Sstevel@tonic-gateis maintained as a Texinfo manual.  If the
4597c478bd9Sstevel@tonic-gate.B info
4607c478bd9Sstevel@tonic-gateand
4617c478bd9Sstevel@tonic-gate.B $program
4627c478bd9Sstevel@tonic-gateprograms are properly installed at your site, the command
4637c478bd9Sstevel@tonic-gate.IP
4647c478bd9Sstevel@tonic-gate.B info $program
4657c478bd9Sstevel@tonic-gate.PP
4667c478bd9Sstevel@tonic-gateshould give you access to the complete manual.
4677c478bd9Sstevel@tonic-gateEOT
4687c478bd9Sstevel@tonic-gate}
4697c478bd9Sstevel@tonic-gate
4707c478bd9Sstevel@tonic-gate# Output header.
4717c478bd9Sstevel@tonic-gateprint <<EOT;
4727c478bd9Sstevel@tonic-gate.\\" DO NOT MODIFY THIS FILE!  It was generated by $this_program $this_version.
4737c478bd9Sstevel@tonic-gate.TH $PROGRAM "$section" "$date" "$package $version" FSF
4747c478bd9Sstevel@tonic-gateEOT
4757c478bd9Sstevel@tonic-gate
4767c478bd9Sstevel@tonic-gate# Section ordering.
4777c478bd9Sstevel@tonic-gatemy @pre = qw(NAME SYNOPSIS DESCRIPTION OPTIONS EXAMPLES);
4787c478bd9Sstevel@tonic-gatemy @post = ('AUTHOR', 'REPORTING BUGS', 'COPYRIGHT', 'SEE ALSO');
4797c478bd9Sstevel@tonic-gatemy $filter = join '|', @pre, @post;
4807c478bd9Sstevel@tonic-gate
4817c478bd9Sstevel@tonic-gate# Output content.
4827c478bd9Sstevel@tonic-gatefor (@pre, (grep ! /^($filter)$/o, @include), @post)
4837c478bd9Sstevel@tonic-gate{
4847c478bd9Sstevel@tonic-gate    if ($include{$_})
4857c478bd9Sstevel@tonic-gate    {
4867c478bd9Sstevel@tonic-gate	my $quote = /\W/ ? '"' : '';
4877c478bd9Sstevel@tonic-gate	print ".SH $quote$_$quote\n";
4887c478bd9Sstevel@tonic-gate
4897c478bd9Sstevel@tonic-gate	for ($include{$_})
4907c478bd9Sstevel@tonic-gate	{
4917c478bd9Sstevel@tonic-gate	    # Replace leading dot, apostrophe and backslash tokens.
4927c478bd9Sstevel@tonic-gate	    s/\x80/\\&./g;
4937c478bd9Sstevel@tonic-gate	    s/\x81/\\&'/g;
4947c478bd9Sstevel@tonic-gate	    s/\x82/\\e/g;
4957c478bd9Sstevel@tonic-gate	    print;
4967c478bd9Sstevel@tonic-gate	}
4977c478bd9Sstevel@tonic-gate    }
4987c478bd9Sstevel@tonic-gate}
4997c478bd9Sstevel@tonic-gate
5007c478bd9Sstevel@tonic-gateexit;
5017c478bd9Sstevel@tonic-gate
5027c478bd9Sstevel@tonic-gate# Convert option dashes to \- to stop nroff from hyphenating 'em, and
5037c478bd9Sstevel@tonic-gate# embolden.  Option arguments get italicised.
5047c478bd9Sstevel@tonic-gatesub convert_option
5057c478bd9Sstevel@tonic-gate{
5067c478bd9Sstevel@tonic-gate    local $_ = '\fB' . shift;
5077c478bd9Sstevel@tonic-gate
5087c478bd9Sstevel@tonic-gate    s/-/\\-/g;
5097c478bd9Sstevel@tonic-gate    unless (s/\[=(.*)\]$/\\fR[=\\fI$1\\fR]/)
5107c478bd9Sstevel@tonic-gate    {
5117c478bd9Sstevel@tonic-gate	s/=(.)/\\fR=\\fI$1/;
5127c478bd9Sstevel@tonic-gate	s/ (.)/ \\fI$1/;
5137c478bd9Sstevel@tonic-gate	$_ .= '\fR';
5147c478bd9Sstevel@tonic-gate    }
5157c478bd9Sstevel@tonic-gate
5167c478bd9Sstevel@tonic-gate    $_;
5177c478bd9Sstevel@tonic-gate}
518