#! /usr/bin/perl
#
# Does a first approximation of converting a BSD man page into something
# suitable for GNO.  Note that you still have to review the output of
# this filter -- no everything is handled, nor is everything handled 
# correctly.
#
# $Id: bsd2man,v 1.1 1997/03/05 04:43:54 gdr Exp $
#
# Devin Reade, December 1996
#

$last_nm = '';			# previously used function name
$title_printed = 0;		# has the title line been printed?

$chapterNames{'0'} = 'General Information';
$chapterNames{'1'} = 'Commands and Applications';
$chapterNames{'2'} = 'System Calls';
$chapterNames{'3'} = 'Library Routines';
$chapterNames{'4'} = 'Devices';
$chapterNames{'5'} = 'File Formats';
$chapterNames{'6'} = 'Games';
$chapterNames{'7'} = 'Miscellaneous';
$chapterNames{'8'} = 'System Administration';
$chapterNames{'L'} = 'Local';
$chapterNames{'N'} = 'New';

$authorCount = 0;

while (<>) {
    chop;
    study;

    # ignore the following (no change in behavior)
    #   .sp
    #   .I

    if (/^.%A\s+(.*)$/) {	# authors
	$line = $1;
	$line =~ s/\s+$//;
	$authors[$authorCount++] = $line;
	next;

    } else {
	if ($authorCount > 0) {
	    printf("by\n");
	    for ($i=0; $i<$authorCount-1; $i++) {
		printf("%s,\n", $authors[$i]);
	    }
	    printf("%s.\n", $authors[$authorCount-1]);
	    $authorCount = 0;
	}
    }

    if (/^\.It\s+Bq\s+Er\s+(.*)$/) { # list item
	$line = $1;
	$line =~ s/\s+$//;
	printf(".IP \\fB%s\\fR\n", $line);

    } elsif (/^\.(sp|I|\\\"|if)/) {		# pass through verbatim
	printf("%s\n", $_);

    } elsif (/^\.(Ar|Dv|El|Pp|Re|Rs|Sh|Va|%B|%T)/) { # simple replacement
	$oldval = $1;
	($oldval eq 'Ar') && (s/$oldval/BR/); # argument
	($oldval eq 'Dv') && (s/$oldval/BR/); # macro value (approx)
	($oldval eq 'El') && (s/$oldval/RE/); # end list
	($oldval eq 'Pp') && (s/$oldval/LP/); # paragraph
	($oldval eq 'Re') && (s/$oldval/RE/); # relative indent end
	($oldval eq 'Rs') && (s/$oldval/RS/); # relative indent start
	($oldval eq 'Va') && (s/$oldval/IR/); # variable
	($oldval eq '%B') && (s/$oldval/B/);  # programmer's sup docs
	($oldval eq '%T') && (s/$oldval/I/);  # title
	if ($oldval eq 'Sh') {	# section header
	    if ($title_printed == 0) {
		$title_printed++;
		
		printf(".TH %s %s %s %s \"%s\"\n", $pagename, $chapter, $date,
		       $os, defined($chapterNames{$chapter}) ?
		       $chapterNames{$chapter} : '(unlisted chapter)');
	    }
	    s/$oldval/SH/;
	}
	printf("%s\n", $_);

    } elsif (/^\.Xr\s+(\S+)\s*(.*)$/) {	# cross reference
	$xref = $1;
	$rest = $2;
	if ($rest =~ /^\d+/) {
	    $section = int($&);
	    $rest = $';
	} else {
	    $section = -1;
	}
	$rest =~ s/\s+//g;
	if ($section == -1) {
	    printf(".BR %s %s\n", $xref, $rest);
	} else {
	    printf(".BR %s (%s)%s\n", $xref, $section, $rest);
	}
	
    } elsif (/^\.(Nm)\s*$/) {	# missing referent
	$oldval = $1;
	($oldval eq 'Nm') && printf(".BR %s\n", $last_nm);

    } elsif (/^\.(Nm)\s+([\"\'][^\"\']*[\"\'])\s*(.*)$/) {
	# quoted first argument
	$oldval = $1;
	$first = $2;
	$rest = $3;

	if ($oldval eq 'Nm') {
	    $last_nm = $first;
	    $oldval = 'BR';
	}
	if (($rest =~ /\s/) && !($rest =~ /[\"\']/)) {
	    printf(".%s %s \"%s\"\n", $oldval, $first, $rest);
	} else {
	    printf(".%s %s %s\n", $oldval, $first, $rest);
	}

    } elsif (/^\.(Nm)\s+(\S+)\s*(.*)$/) {
	# unquoted first argument
	$oldval = $1;
	$first = $2;
	$rest = $3;

	if ($oldval eq 'Nm') {
	    $last_nm = $first;
	    s/$oldval/BR/;
	}
	printf ("%s\n", $_);

    } elsif (/^\.Fd\s+(.*)$/) {	# function define (?)
	printf(".br\n%s\n", $1);
	
    } elsif (/^\.Ft\s+(.*)$/) {	# function type
	printf(".sp 1\n%s\n", $1);
	
    } elsif (/^\.Fn\s+(\S+)\s*(.*)$/) {	# function name, perhaps with protos
	$n = $1;
	$rest = $2;
	if ($rest =~ /[\"\']/) {
	    $rest =~ s/^\s*[\"\']/\(/;
	    $rest =~ s/\"\s+\"/, /g;
	    $rest =~ s/[\"\']\s*$/\);/;
	    printf ("%s %s\n", $n, $rest);
	} else {
	    printf (".BR %s %s\n", $n, $rest);
	}

    } elsif (/^\.Fa\s+(.*)$/) {	# function argument
	$line = $1;
	$line =~ s/\s+$//;
	if (($line =~ /^\S+$/) || ($line =~ /[\"\']([^\"\']+)[\"\']/)) {
	    printf(".I %s\n", $line);
	} elsif ($line =~ /\(?(\S+)\)?/) {
	    printf(".RI ( %s )\n", $1);
	} else {
	    printf(".IR %s\n", $line);
	}

    } elsif (/^\.Em/) {
	@line = split;
	shift @line;
	$line = '';
	$firstword = '';
	$word = shift @line;
	if ($word =~ /([\'\"])/) { # get the emphasized part
	    $quote = $1;
	    $firstword .= $word;
	    do {
		$word = shift @line;
		$firstword .= ' ' . $word;
	    } while (($word ne '') && !($word =~ /$quote/));
	} else {
	    $firstword .= $word;
	}
	$skip_space = 1;
	$quote = '"';
	foreach $w (@line) {
	    ($quote eq '"') && ($line .= ' '.$quote) && ($quote = '');
	    ($w eq 'Ns') && ($skip_space = 1) && next;
	    ($w eq 'Ap') && ($skip_space = 1) && ($line .= "'") && next;
	    if ($skip_space == 1) {
		$line .= $w;
		$skip_space = 0;
	    } else {
		$line .= ' ' . $w;
	    }
	}
	($quote eq '') && ($line .= '"');
	if ($line =~ /^\s*"(\S+)"\s*$/) { # dump unecessary quotes
	    $line = $1;
	}
	printf(".IR %s %s\n", $firstword, $line);

    } elsif (/^\.Dd\s+[\"\']?([^\"\']+)[\"\']?/) { # date
	$date = '"' . $1 . '"';

    } elsif (/^\.Os\s+(.*)$/) {	# specified operating system
	$os = $1;
	$os =~ s/\s+$//;
	$os =~ s/[\"\']//g;
	if (! $os =~ /\d+\.\d+/) {
	    $os =~ s/BSD\s+/BSD 4./;
	}
	$os = '"' . $os . '"';

    } elsif (/^\.Os\s*$/) {	# unspecified operating system
	$os = '""';

    } elsif (/^\.Dt\s+(.*)\s+(\d+[\S]*)\s*$/) {	# name and section number
	$pagename = $1;
	$chapter = $2;
	$chapter =~ /(\d+)/;
	$chapternumber = $&;
	if (($pagename =~ /\s/) && !($pagename =~ /[\"\']/)) {
	    $pagename = '"' . $pagename . '"';
	}

    } elsif (/^\.Nd\s+[\"\']?([^\"\']+)[\"\']?/) { # brief description
	printf ("\\- %s\n", $1);

    } elsif (/^\.Bx\s+(\d+\.\d+)(.*)$/) { # BSD version
	s/^\.Bx/BSD/;
	s/\s+Reno\s+/ \(Reno\) /g;
	s/\s+\.\s*$/./;
	printf("%s\n", $_);

    } elsif (/^\.Bl\s+/) {	# begin list
	printf(".RS\n");

    } elsif (/^(\.%N)/) {	# volume number.  See .%B above.
	s/$1/volume/;
	printf("%s\n", $_);

    } elsif (/^\./) {		# catch unrecognised commands
	printf(STDERR "Unknown command line %d: %s\n", $., $_);
	printf("%s\n", $_);

    } else {			# normal line
	printf("%s\n", $_);
    }
}
