5a9b54
=head1 NAME
5a9b54
5a9b54
docbook2man-spec.pl - convert DocBook RefEntries to Unix manpages
5a9b54
5a9b54
=head1 SYNOPSIS
5a9b54
5a9b54
The sgmlspl script from the SGMLSpm Perl module must be used to run
5a9b54
this script.  Use it like this:
5a9b54
5a9b54
nsgmls some-docbook-document.sgml | sgmlspl docbook2man-spec.pl
5a9b54
5a9b54
See man page or included DocBook documentation for details.
5a9b54
5a9b54
=head1 DESCRIPTION
5a9b54
5a9b54
This is a sgmlspl spec file that produces Unix-style
5a9b54
man pages from DocBook RefEntry markup.
5a9b54
5a9b54
=head1 COPYRIGHT
5a9b54
5a9b54
Copyright (C) 1998-2001 Steve Cheng <stevecheng@users.sourceforge.net>
5a9b54
5a9b54
Copyright (C) 1999 Thomas Lockhart <lockhart@alumni.caltech.edu>
5a9b54
5a9b54
This program is free software; you can redistribute it and/or modify it
5a9b54
under the terms of the GNU General Public License as published by the Free
5a9b54
Software Foundation; either version 2, or (at your option) any later
5a9b54
version.
5a9b54
5a9b54
You should have received a copy of the GNU General Public License along with
5a9b54
this program; see the file COPYING.  If not, please write to the Free
5a9b54
Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
5a9b54
5a9b54
=cut
5a9b54
5a9b54
# $Id: docbook2man-spec.pl,v 1.11 2010/10/04 10:23:31 ovasik Exp $
5a9b54
5a9b54
use SGMLS;			# Use the SGMLS package.
5a9b54
use SGMLS::Output;		# Use stack-based output.
5a9b54
use SGMLS::Refs;
5a9b54
5a9b54
5a9b54
########################################################################
5a9b54
# SGMLSPL script produced automatically by the script sgmlspl.pl
5a9b54
#
5a9b54
# Document Type: any, but processes only RefEntries
5a9b54
# Edited by: me :)
5a9b54
########################################################################
5a9b54
5a9b54
5a9b54
$write_manpages = 0;
5a9b54
$blank_xrefs = 0;
5a9b54
5a9b54
$default_sect = "1";
5a9b54
$default_date = `date "+%d %B %Y"`;
5a9b54
$cite_numeral_only = 1;
5a9b54
5a9b54
while (@ARGV) {
5a9b54
	my $arg = shift @ARGV;
5a9b54
	if ($arg eq "--section") {
5a9b54
		$default_sect = shift @ARGV || die "$arg requires an argument\n";
5a9b54
	} elsif ($arg eq "--date") {
5a9b54
		$default_date = shift @ARGV || die "$arg requires an argument\n";
5a9b54
	} elsif ($arg eq "--lowercase") {
5a9b54
		$lowercase_names = 1;
5a9b54
	} elsif ($arg eq "--preserve-case") {
5a9b54
		$lowercase_names = 0;
5a9b54
	} elsif ($arg eq "--cite-numeral-only") {
5a9b54
		$cite_numeral_only = 1;
5a9b54
	} elsif ($arg eq "--nocite-numeral-only") {
5a9b54
		$cite_numeral_only = 0;
5a9b54
	} elsif ($arg eq "--help") {
5a9b54
		print "Usage: $0",
5a9b54
			" [ --section <label> ]",
5a9b54
			" [ --date <string> ]",
5a9b54
			" [ --lowercase | --preserve-case ]",
5a9b54
			" [ --cite-numeral-only | --nocite-numeral-only ]",
5a9b54
			"\n";
5a9b54
		exit;
5a9b54
	} else {
5a9b54
		die "unrecognized switch $arg; try $0 --help\n";
5a9b54
	}
5a9b54
}
5a9b54
5a9b54
sgml('start', sub { 
5a9b54
	push_output('nul');
5a9b54
	$raw_cdata = 1;			# Makes it a bit faster.
5a9b54
	
5a9b54
	# Links file
5a9b54
	open(LINKSFILE, ">manpage.links");
5a9b54
5a9b54
	$Refs = new SGMLS::Refs("manpage.refs", "manpage.log");
5a9b54
});
5a9b54
sgml('end', sub {
5a9b54
	close(LINKSFILE);
5a9b54
5a9b54
	# Explicitly invoke destructor,
5a9b54
	# otherwise cache file may not get written!
5a9b54
	# Thomas Lockhart, 1999-08-03, perl-5.004, RedHat5.2
5a9b54
	undef $Refs;
5a9b54
5a9b54
	if($blank_xrefs) {
5a9b54
		warn "Warning: output contains unresolved XRefs\n";
5a9b54
	}
5a9b54
});
5a9b54
5a9b54
5a9b54
########################################################################
5a9b54
#
5a9b54
# Output helpers 
5a9b54
#
5a9b54
########################################################################
5a9b54
5a9b54
# Remove leading and trailing blanks.
5a9b54
5a9b54
sub StripString
5a9b54
{
5a9b54
	my $str = shift;
5a9b54
5a9b54
	$str = $1 if ($str =~ m#^\s*(\S.*)#);
5a9b54
	$str = $1 if ($str =~ m#^(.*\S)\s*$#);
5a9b54
5a9b54
	return $str;
5a9b54
}
5a9b54
5a9b54
# Generate a good file name, for given manpage title and manvolnum
5a9b54
# (cdata content).
5a9b54
# Cleanup whitespace and convert to lower case if required.
5a9b54
5a9b54
sub FileInfo
5a9b54
{
5a9b54
	my $title = StripString(shift);
5a9b54
	my $volnum = StripString(shift);
5a9b54
5a9b54
	$title = lc $title if $lowercase_names;
5a9b54
5a9b54
	$title =~ tr/ /_/;
5a9b54
	$volnum =~ tr/ /_/;
5a9b54
5a9b54
	my $sectcite = $volnum;
5a9b54
	# The 'package name' part of the section should
5a9b54
	# not be used when citing it.
5a9b54
	if ($cite_numeral_only) {
5a9b54
		$sectcite = $1 if ($volnum =~ /^([0-9]+)/);
5a9b54
	}
5a9b54
	
5a9b54
	return ("$title.$volnum", "$title($sectcite)");
5a9b54
}
5a9b54
5a9b54
# Our own version of sgml() and output() to allow simple string output
5a9b54
# to play well with roff's stupid whitespace rules. 
5a9b54
5a9b54
sub man_sgml
5a9b54
{
5a9b54
	if(ref($_[1]) eq 'CODE') {
5a9b54
		return &sgml;
5a9b54
	}
5a9b54
	
5a9b54
	my $s = $_[1];
5a9b54
	$s =~ s/\\/\\\\/g;
5a9b54
	$s =~ s/'/\\'/g;
5a9b54
5a9b54
	sgml($_[0], eval("sub { man_output '$s' }"));
5a9b54
}
5a9b54
5a9b54
sub man_output
5a9b54
{
5a9b54
	if($separator eq 'full') {
5a9b54
		output "\n" unless $newline_last++;
5a9b54
		output ".PP\n";
5a9b54
		$separator = '';
5a9b54
	}
5a9b54
	
5a9b54
	$_ = shift;
5a9b54
	if(s/^\n//) {
5a9b54
		output "\n" unless $newline_last++;
5a9b54
	}
5a9b54
	return if $_ eq '';
5a9b54
	
5a9b54
	output $_;
5a9b54
5a9b54
	if(@_) {
5a9b54
		output @_;
5a9b54
		$newline_last = (pop(@_) =~ /\n$/);
5a9b54
	} else {
5a9b54
		$newline_last = ($_ =~ /\n$/)
5a9b54
	}
5a9b54
}
5a9b54
5a9b54
# Fold lines into one, quote some characters
5a9b54
sub fold_string
5a9b54
{
5a9b54
	$_ = shift;
5a9b54
	
5a9b54
	s/\\/\\\\/g;
5a9b54
	s/"/""/g;
5a9b54
5a9b54
	# Change tabs and newlines to spaces
5a9b54
	# The newlines will be swallowed later while trimming
5a9b54
	tr/[\t\n]/  /;
5a9b54
5a9b54
	# Trim whitespace from beginning and end.
5a9b54
	s/^ +//;
5a9b54
	s/ +$//;
5a9b54
5a9b54
	return $_;
5a9b54
}
5a9b54
	
5a9b54
sub save_cdata()
5a9b54
{
5a9b54
	$raw_cdata++;
5a9b54
	push_output('string');
5a9b54
}
5a9b54
5a9b54
sub bold_on()
5a9b54
{
5a9b54
	# If the last font is also bold, don't change anything.
5a9b54
	# Basically this is to just get more readable man output.
5a9b54
	if($fontstack[$#fontstack] ne 'bold') {
5a9b54
		if(!$raw_cdata) {
5a9b54
			output '\fB';
5a9b54
			#$newline_last = 0;
5a9b54
		}
5a9b54
	}
5a9b54
	push(@fontstack, 'bold');
5a9b54
}
5a9b54
5a9b54
sub italic_on()
5a9b54
{
5a9b54
	# If the last font is also italic, don't change anything.
5a9b54
	if($fontstack[$#fontstack] ne 'italic') {
5a9b54
		if(!$raw_cdata) {
5a9b54
			output '\fI';
5a9b54
			#$newline_last = 0;
5a9b54
		}
5a9b54
	}
5a9b54
	push(@fontstack, 'italic');
5a9b54
}
5a9b54
5a9b54
sub font_off()
5a9b54
{
5a9b54
	my $thisfont = pop(@fontstack);
5a9b54
	my $lastfont = $fontstack[$#fontstack];
5a9b54
	
5a9b54
	# Only output font change if it is different
5a9b54
	if($thisfont ne $lastfont) {
5a9b54
		if($raw_cdata)			{ return; }
5a9b54
		elsif($lastfont eq 'bold') 	{ output '\fB'; }
5a9b54
		elsif($lastfont eq 'italic')	{ output '\fI'; }
5a9b54
		else				{ output '\fR'; }
5a9b54
	
5a9b54
		#$newline_last = 0;
5a9b54
	}
5a9b54
}
5a9b54
5a9b54
5a9b54
########################################################################
5a9b54
#
5a9b54
# Manpage management
5a9b54
#
5a9b54
########################################################################
5a9b54
5a9b54
sgml('<REFENTRY>', sub { 
5a9b54
	# This will be overwritten at end of REFMETA, when we know the name of the page.
5a9b54
	pop_output();
5a9b54
	
5a9b54
	$write_manpages = 1;		# Currently writing manpage.
5a9b54
	
5a9b54
	$nocollapse_whitespace = 0;	# Current whitespace collapse counter.
5a9b54
	$newline_last = 1;		# At beginning of line?
5a9b54
		# Just a bit of warning, you will see this variable manipulated
5a9b54
		# manually a lot.  It makes the code harder to follow but it
5a9b54
		# saves you from having to worry about collapsing at the end of
5a9b54
		# parse, stopping at verbatims, etc.
5a9b54
	$raw_cdata = 0;                 # Instructs certain output functions to
5a9b54
					# leave CDATA alone, so we can assign
5a9b54
					# it to a string and process it, etc.
5a9b54
	@fontstack = ();		# Fonts being activated.
5a9b54
	
5a9b54
	$list_nestlevel = 0;		# Indent certain nested content.
5a9b54
5a9b54
	# Separator to use between 'elements' in the content of a
5a9b54
	# paragraph (usually).  This makes sure that PCDATA after a list
5a9b54
	# in a PARA gets a break in between and not become part of the
5a9b54
	# last listitem.  Note that we can't do it after the list ends,
5a9b54
	# because often the list ends the paragraph and we'll get an
5a9b54
	# extra break.  Anything that changes the separator status from
5a9b54
	# the default should also save its last state in the parent
5a9b54
	# element's ext, but I'm not going to explain further.  It's a
5a9b54
	# gross hack and almost guaranteed to fail in unforseen cases.
5a9b54
	# The only way to avoid all this is to use a tree/grove model, which
5a9b54
	# we're _not_ doing.
5a9b54
	$separator = '';
5a9b54
	
5a9b54
	$manpage_title = '';		# Needed for indexing.
5a9b54
	$manpage_sect = '';
5a9b54
	@manpage_names = ();
5a9b54
	
5a9b54
	$manpage_misc = '';
5a9b54
5a9b54
	# check refentry's language
5a9b54
	if(defined($_[0]->attribute('LANG')->value)) {
5a9b54
	  $manpage_lang = $_[0]->attribute('LANG')->value;
5a9b54
	}
5a9b54
	else {
5a9b54
	  $manpage_lang = '';
5a9b54
	}
5a9b54
});
5a9b54
sgml('</REFENTRY>', sub {
5a9b54
	if(!$newline_last) {
5a9b54
		output "\n";
5a9b54
	}
5a9b54
	
5a9b54
	$raw_cdata = 1;
5a9b54
	push_output('nul');
5a9b54
5a9b54
	$write_manpages = 0;
5a9b54
});
5a9b54
5a9b54
sgml('</REFMETA>', sub {
5a9b54
	my ($filename, $citation) = 
5a9b54
		FileInfo($manpage_title, $manpage_sect || $default_sect);
5a9b54
5a9b54
	push_output('file', $filename);
5a9b54
5a9b54
	output <<'_END_BANNER';
5a9b54
.\" auto-generated by docbook2man-spec from docbook-utils package
5a9b54
_END_BANNER
5a9b54
5a9b54
	my $manpage_date = $_[0]->parent->ext->{'date'} || $default_date;
5a9b54
5a9b54
	output '.TH "';
5a9b54
5a9b54
	# If the title is not mixed-case, convention says to
5a9b54
	# uppercase the whole title.  (The canonical title is
5a9b54
	# lowercase.)
5a9b54
	if($manpage_title =~ /[A-Z]/) {
5a9b54
		output fold_string($manpage_title);
5a9b54
	} else {
5a9b54
		output uc(fold_string($manpage_title));
5a9b54
	}
5a9b54
	
5a9b54
	output  '" "', fold_string($manpage_sect), 
5a9b54
		'" "', fold_string($manpage_date),
5a9b54
		'" "', $manpage_misc, 
5a9b54
		'" "', $manpage_manual, 
5a9b54
		"\"\n";
5a9b54
5a9b54
	$newline_last = 1;
5a9b54
5a9b54
	# References to this RefEntry.
5a9b54
	if(defined($_[0]->parent->attribute('ID')->value)) {
5a9b54
		my $id = $_[0]->parent->attribute('ID')->value;
5a9b54
5a9b54
		# Append XREFLABEL content to citations.
5a9b54
		if(defined($_[0]->parent->attribute('XREFLABEL')->value)) {
5a9b54
			$citation = $_[0]->parent->attribute('XREFLABEL')->value .
5a9b54
					' [' . $citation . ']';
5a9b54
		}
5a9b54
5a9b54
		$Refs->put("refentry:$id", $citation);
5a9b54
	}
5a9b54
});
5a9b54
5a9b54
sgml('<REFENTRYTITLE>', sub { 
5a9b54
	if($_[0]->in('REFMETA')) { 
5a9b54
		save_cdata();
5a9b54
	} else { 
5a9b54
		# Manpage citations are in bold.
5a9b54
		bold_on();
5a9b54
	}
5a9b54
});
5a9b54
sgml('</REFENTRYTITLE>', sub { 
5a9b54
	if($_[0]->in('REFMETA')) {
5a9b54
		$raw_cdata--;
5a9b54
		$manpage_title = pop_output();
5a9b54
	}
5a9b54
	else { font_off(); }
5a9b54
5a9b54
	if (defined($_[0]->attribute('ID')->value)) {
5a9b54
		my $id = $_[0]->attribute('ID')->value;
5a9b54
		$Refs->put("refentrytitle:$id", $manpage_title);
5a9b54
	}
5a9b54
});
5a9b54
5a9b54
sgml('<MANVOLNUM>', sub { 
5a9b54
	if($_[0]->in('REFMETA')) { 
5a9b54
		save_cdata();	
5a9b54
	} else {
5a9b54
		# Manpage citations use ().
5a9b54
		output '(';
5a9b54
	}
5a9b54
});
5a9b54
sgml('</MANVOLNUM>', sub { 
5a9b54
	if($_[0]->in('REFMETA')) {
5a9b54
		$raw_cdata--;
5a9b54
		$manpage_sect = pop_output();
5a9b54
	}
5a9b54
	else { output ')' }
5a9b54
});
5a9b54
5a9b54
sgml('<REFMISCINFO>', \&save_cdata);
5a9b54
sgml('</REFMISCINFO>', sub { 
5a9b54
	$raw_cdata--;
5a9b54
	$manpage_misc = fold_string(pop_output());
5a9b54
});
5a9b54
5a9b54
5a9b54
# NAME section
5a9b54
#man_sgml('<REFNAMEDIV>', "\n.SH NAME\n");
5a9b54
man_sgml('<REFNAMEDIV>', sub {
5a9b54
	my %text = { fr=>'NOM', es=>'NOMBRE', pl=>'NAZWA' };
5a9b54
	
5a9b54
	if(defined $text{lc($manpage_lang)})
5a9b54
	{
5a9b54
		man_output "\n.SH " . $text{lc($manpage_lang)} . "\n";
5a9b54
	} elsif(defined $_[0]->attribute('LANG') and
5a9b54
		defined $text{lc($_[0]->attribute('LANG')->value)})
5a9b54
	{
5a9b54
		man_output "\n.SH " . $text{lc($_[0]->attribute('LANG'))} . "\n";
5a9b54
	} else {
5a9b54
		man_output "\n.SH NAME\n";
5a9b54
	}
5a9b54
});
5a9b54
5a9b54
sgml('<REFNAME>', \&save_cdata);
5a9b54
sgml('</REFNAME>', sub { 
5a9b54
	$raw_cdata--;
5a9b54
	push(@manpage_names, pop_output());
5a9b54
});
5a9b54
5a9b54
sgml('<REFPURPOSE>', \&save_cdata);
5a9b54
sgml('</REFPURPOSE>', sub { 
5a9b54
	$raw_cdata--;
5a9b54
	my $manpage_purpose = fold_string(pop_output());
5a9b54
	
5a9b54
	for(my $i = 0; $i < $#manpage_names; $i++) {
5a9b54
		output fold_string($manpage_names[$i]), ', ';
5a9b54
	}
5a9b54
5a9b54
	output fold_string($manpage_names[$#manpage_names]);
5a9b54
	output " \\- $manpage_purpose\n";
5a9b54
5a9b54
	$newline_last = 1;
5a9b54
5a9b54
	foreach(@manpage_names) {
5a9b54
		# Don't link to itself
5a9b54
		if($_ ne $manpage_title) {
5a9b54
			print LINKSFILE "$manpage_title.$manpage_sect	$_.$manpage_sect\n";
5a9b54
		}
5a9b54
	}
5a9b54
});
5a9b54
	
5a9b54
man_sgml('<REFCLASS>', "\n.sp\n");
5a9b54
5a9b54
#RefDescriptor
5a9b54
5a9b54
5a9b54
########################################################################
5a9b54
#
5a9b54
# SYNOPSIS section and synopses
5a9b54
#
5a9b54
########################################################################
5a9b54
5a9b54
#man_sgml('<REFSYNOPSISDIV>', "\n.SH SYNOPSIS\n");
5a9b54
man_sgml('<REFSYNOPSISDIV>', sub {
5a9b54
	   if ($manpage_lang eq "pl") { man_output "\n.SH SK£ADNIA\n"; }
5a9b54
	   # waits for another languages
5a9b54
	   #elsif ($manpage_lang eq "xx") { man_output "\n.SH xxxxxxx\n"; } 
5a9b54
	   else { man_output "\n.SH SYNOPSIS\n"; }
5a9b54
});   
5a9b54
5a9b54
man_sgml('</REFSYNOPSISDIV>', "\n");
5a9b54
5a9b54
## FIXME! Must be made into block elements!!
5a9b54
#sgml('<FUNCSYNOPSIS>', \&bold_on);
5a9b54
#sgml('</FUNCSYNOPSIS>', \&font_off);
5a9b54
#sgml('<CMDSYNOPSIS>', \&bold_on);
5a9b54
#sgml('</CMDSYNOPSIS>', \&font_off);
5a9b54
5a9b54
man_sgml('<FUNCSYNOPSIS>', sub {
5a9b54
	man_output("\n.nf\n");
5a9b54
	bold_on();
5a9b54
});
5a9b54
man_sgml('</FUNCSYNOPSIS>', sub {
5a9b54
	man_output("\n.fi");
5a9b54
	font_off();
5a9b54
});
5a9b54
5a9b54
man_sgml('<CMDSYNOPSIS>', "\n.sp\n");
5a9b54
man_sgml('</CMDSYNOPSIS>', "\n");
5a9b54
5a9b54
man_sgml('<FUNCPROTOTYPE>', "\n.sp\n");
5a9b54
5a9b54
# Arguments to functions.  This is C convention.
5a9b54
#man_sgml('<PARAMDEF>', '(');
5a9b54
#man_sgml('</PARAMDEF>', ");\n");
5a9b54
#man_sgml('<VOID>', "(void);\n");
5a9b54
sub paramdef
5a9b54
{
5a9b54
	if($_[0]->parent->ext->{'inparams'}) {
5a9b54
		output ', ';
5a9b54
	} else {
5a9b54
		output ' (';
5a9b54
		$_[0]->parent->ext->{'inparams'} = 1;
5a9b54
	}
5a9b54
}
5a9b54
man_sgml('<PARAMDEF>', \&paramdef);
5a9b54
man_sgml('</FUNCPROTOTYPE>', ");\n");
5a9b54
man_sgml('<VOID>', "(void");
5a9b54
man_sgml('<VARARGS>', "(...");
5a9b54
5a9b54
5a9b54
sub arg_start
5a9b54
{
5a9b54
	# my $choice = $_[0]->attribute('CHOICE')->value;
5a9b54
5a9b54
	# The content model for CmdSynopsis doesn't include #PCDATA,
5a9b54
	# so we won't see any of the whitespace in the source file,
5a9b54
	# so we have to add it after each component.
5a9b54
	man_output ' ';
5a9b54
5a9b54
	if($_[0]->attribute('CHOICE')->value =~ /opt/i) {
5a9b54
		man_output '[ ';
5a9b54
	}
5a9b54
	bold_on();
5a9b54
}
5a9b54
sub arg_end
5a9b54
{
5a9b54
	font_off();
5a9b54
	if($_[0]->attribute('REP')->value =~ /^Repeat/i) {
5a9b54
		italic_on();
5a9b54
		man_output '...';
5a9b54
		font_off();
5a9b54
	}
5a9b54
	if($_[0]->attribute('CHOICE')->value =~ /opt/i) {
5a9b54
		man_output ' ] ';
5a9b54
	}
5a9b54
}
5a9b54
5a9b54
sgml('<ARG>', \&arg_start);
5a9b54
sgml('</ARG>', \&arg_end);
5a9b54
sgml('<GROUP>', \&arg_start);
5a9b54
sgml('</GROUP>', \&arg_end);
5a9b54
5a9b54
sgml('<OPTION>', \&bold_on);
5a9b54
sgml('</OPTION>', \&font_off);
5a9b54
5a9b54
# FIXME: This is one _blank_ line.
5a9b54
man_sgml('<SBR>', "\n\n");
5a9b54
5a9b54
5a9b54
########################################################################
5a9b54
#
5a9b54
# General sections
5a9b54
#
5a9b54
########################################################################
5a9b54
5a9b54
# The name of the section is handled by TITLE.  This just sets
5a9b54
# up the roff markup.
5a9b54
man_sgml('<REFSECT1>', sub { $separator = ''; man_output "\n.SH "});
5a9b54
man_sgml('<REFSECT2>', sub { $separator = ''; man_output "\n.SS "});
5a9b54
man_sgml('<REFSECT3>', sub { $separator = ''; man_output "\n.SS "});
5a9b54
5a9b54
5a9b54
########################################################################
5a9b54
#
5a9b54
# Titles, metadata.
5a9b54
#
5a9b54
########################################################################
5a9b54
5a9b54
sgml('<TITLE>', sub {
5a9b54
	if($_[0]->in('REFERENCE') or $_[0]->in('BOOK')) {
5a9b54
		$write_manpages = 1;
5a9b54
	}
5a9b54
	save_cdata();
5a9b54
});
5a9b54
sgml('</TITLE>', sub {
5a9b54
	my ($element, $event) = @_;
5a9b54
	my $title = fold_string(pop_output());
5a9b54
	$raw_cdata--;
5a9b54
	
5a9b54
	if($element->in('REFERENCE') or $element->in('BOOK')) {
5a9b54
		# We use TITLE of enclosing Reference or Book as manual name
5a9b54
		$manpage_manual = $title;
5a9b54
		$write_manpages = 0;
5a9b54
	}
5a9b54
	elsif(exists $element->parent->ext->{'title'}) {
5a9b54
		# By far the easiest case.  Just fold the string as
5a9b54
		# above, and then set the parent element's variable.
5a9b54
		$_[0]->parent->ext->{'title'} = $title;
5a9b54
	}
5a9b54
	else {
5a9b54
		# If the parent element's handlers are lazy, 
5a9b54
		# output the folded string for them :)
5a9b54
		# We assume they want uppercase and a newline.
5a9b54
		man_output '"', uc($title), "\"\n";
5a9b54
	}
5a9b54
5a9b54
	if (defined($element->attribute('ID')->value)) {
5a9b54
		my $id = $_[0]->attribute('ID')->value;
5a9b54
		$Refs->put("title:$id", $title);
5a9b54
	}
5a9b54
5a9b54
	my ($filename, $citation) =
5a9b54
		FileInfo($manpage_title, $manpage_sect || $default_sect);
5a9b54
	my $parentid = $element->parent->attribute('ID')->value;
5a9b54
	if ($parentid and ($element->in('REFSECT1') or $element->in('REFSECT2') or $element->in('REFSECT3'))) {
5a9b54
		$Refs->put("refsect:$parentid", "$citation");
5a9b54
	}
5a9b54
});
5a9b54
5a9b54
sgml('<ATTRIBUTION>', sub { 
5a9b54
	if($_[0]->in('BLOCKQUOTE')) {
5a9b54
		push_output('string');
5a9b54
	}
5a9b54
});
5a9b54
sgml('</ATTRIBUTION>', sub { 
5a9b54
	if($_[0]->in('BLOCKQUOTE')) {
5a9b54
		$_[0]->parent->ext->{'attribution'} = pop_output(); 
5a9b54
	} else {
5a9b54
		# For an Epigraph.
5a9b54
		man_output "\n\n";
5a9b54
	}
5a9b54
});
5a9b54
5a9b54
sgml('<DATE>', sub {
5a9b54
      save_cdata();
5a9b54
});
5a9b54
sgml('</DATE>', sub {
5a9b54
      $_[0]->parent->parent->ext->{'date'} = fold_string(pop_output());
5a9b54
      $raw_cdata--;
5a9b54
});
5a9b54
5a9b54
sub ignore_content { push_output 'nul'; }
5a9b54
sub restore_content { pop_output(); }
5a9b54
5a9b54
sgml('<DOCINFO>', \&ignore_content);
5a9b54
sgml('</DOCINFO>', \&restore_content);
5a9b54
sgml('<REFSYNOPSISDIVINFO>', \&ignore_content);
5a9b54
sgml('</REFSYNOPSISDIVINFO>', \&restore_content);
5a9b54
sgml('<REFSECT1INFO>', \&ignore_content);
5a9b54
sgml('</REFSECT1INFO>', \&restore_content);
5a9b54
sgml('<REFSECT2INFO>', \&ignore_content);
5a9b54
sgml('</REFSECT2INFO>', \&restore_content);
5a9b54
sgml('<REFSECT3INFO>', \&ignore_content);
5a9b54
sgml('</REFSECT3INFO>', \&restore_content);
5a9b54
5a9b54
sgml('<INDEXTERM>', \&ignore_content);
5a9b54
sgml('</INDEXTERM>', \&restore_content);
5a9b54
5a9b54
sgml('<AUTHORBLURB>', \&ignore_content);
5a9b54
sgml('</AUTHORBLURB>', \&restore_content);
5a9b54
5a9b54
5a9b54
########################################################################
5a9b54
#
5a9b54
# Set bold on enclosed content 
5a9b54
#
5a9b54
########################################################################
5a9b54
5a9b54
sgml('<APPLICATION>', \&bold_on);
5a9b54
sgml('</APPLICATION>', \&font_off);
5a9b54
5a9b54
sgml('<CLASSNAME>', \&bold_on);		sgml('</CLASSNAME>', \&font_off);
5a9b54
sgml('<STRUCTNAME>', \&bold_on);	sgml('</STRUCTNAME>', \&font_off);
5a9b54
sgml('<STRUCTFIELD>', \&bold_on);	sgml('</STRUCTFIELD>', \&font_off);
5a9b54
sgml('<SYMBOL>', \&bold_on);		sgml('</SYMBOL>', \&font_off);
5a9b54
sgml('<TYPE>', \&bold_on);		sgml('</TYPE>', \&font_off);
5a9b54
5a9b54
sgml('<ENVAR>', \&bold_on);	sgml('</ENVAR>', \&font_off);
5a9b54
5a9b54
sgml('<FUNCTION>', \&bold_on);	sgml('</FUNCTION>', \&font_off);
5a9b54
5a9b54
sgml('<EMPHASIS>', \&bold_on);	sgml('</EMPHASIS>', \&font_off);
5a9b54
5a9b54
sgml('<ERRORNAME>', \&bold_on);	sgml('</ERRORNAME>', \&font_off);
5a9b54
# ERRORTYPE
5a9b54
5a9b54
sgml('<COMMAND>', \&bold_on);	sgml('</COMMAND>', \&font_off);
5a9b54
5a9b54
sgml('<GUIBUTTON>', \&bold_on);	sgml('</GUIBUTTON>', \&font_off);
5a9b54
sgml('<GUIICON>', \&bold_on);	sgml('</GUIICON>', \&font_off);
5a9b54
# GUILABEL
5a9b54
# GUIMENU
5a9b54
# GUIMENUITEM
5a9b54
# GUISUBMENU
5a9b54
# MENUCHOICE
5a9b54
5a9b54
sgml('<ACCEL>', \&bold_on);	sgml('</ACCEL>', \&font_off);
5a9b54
# KEYCODE
5a9b54
# SHORTCUT
5a9b54
5a9b54
5a9b54
sgml('<KEYCOMBO>', sub {
5a9b54
	$separator = 'none';
5a9b54
	$_[0]->ext->{'separator'} = 'none';
5a9b54
});
5a9b54
sgml('</KEYCOMBO>', sub { $separator = $_[0]->parent->ext->{'separator'}; });
5a9b54
5a9b54
sub _keycombo {
5a9b54
	if($_[0]->in('KEYCOMBO')) {
5a9b54
		if($separator eq 'none') { $separator = '' }
5a9b54
		else { man_output "+"; }
5a9b54
	}
5a9b54
	bold_on();
5a9b54
}
5a9b54
sgml('<KEYCAP>', \&_keycombo);	sgml('</KEYCAP>', \&font_off);
5a9b54
sgml('<KEYSYM>', \&_keycombo);	sgml('</KEYSYM>', \&font_off);
5a9b54
sgml('<MOUSEBUTTON>', \&_keycombo);	sgml('</MOUSEBUTTON>', \&font_off);
5a9b54
5a9b54
5a9b54
sgml('<USERINPUT>', \&bold_on);	sgml('</USERINPUT>', \&font_off);
5a9b54
5a9b54
sgml('<INTERFACEDEFINITION>', \&bold_on);
5a9b54
sgml('</INTERFACEDEFINITION>', \&font_off);
5a9b54
5a9b54
# May need to look at the CLASS
5a9b54
sgml('<SYSTEMITEM>', \&bold_on);
5a9b54
sgml('</SYSTEMITEM>', \&font_off);
5a9b54
5a9b54
5a9b54
########################################################################
5a9b54
#
5a9b54
# Set italic on enclosed content 
5a9b54
#
5a9b54
########################################################################
5a9b54
5a9b54
sgml('<FIRSTTERM>', \&italic_on);	sgml('</FIRSTTERM>', \&font_off);
5a9b54
5a9b54
sgml('<FILENAME>', \&italic_on);	sgml('</FILENAME>', \&font_off);
5a9b54
sgml('<PARAMETER>', \&italic_on);	sgml('</PARAMETER>', \&font_off);
5a9b54
sgml('<PROPERTY>', \&italic_on);	sgml('</PROPERTY>', \&font_off);
5a9b54
5a9b54
sgml('<REPLACEABLE>', sub {
5a9b54
	italic_on();
5a9b54
	if($_[0]->in('TOKEN')) {
5a9b54
		# When tokenizing, follow more 'intuitive' convention
5a9b54
		output "<";
5a9b54
	}
5a9b54
});
5a9b54
sgml('</REPLACEABLE>', sub {
5a9b54
	if($_[0]->in('TOKEN')) {
5a9b54
		output ">";
5a9b54
	}
5a9b54
	font_off();
5a9b54
});
5a9b54
5a9b54
sgml('<CITETITLE>', \&italic_on);	sgml('</CITETITLE>', \&font_off);
5a9b54
sgml('<FOREIGNPHRASE>', \&italic_on);	sgml('</FOREIGNPHRASE>', \&font_off);
5a9b54
5a9b54
sgml('<LINEANNOTATION>', \&italic_on);	sgml('</LINEANNOTATION>', \&font_off);
5a9b54
5a9b54
5a9b54
########################################################################
5a9b54
#
5a9b54
# Other 'inline' elements 
5a9b54
#
5a9b54
########################################################################
5a9b54
5a9b54
man_sgml('<EMAIL>', '<');
5a9b54
man_sgml('</EMAIL>', '>');
5a9b54
man_sgml('<OPTIONAL>', '[');
5a9b54
man_sgml('</OPTIONAL>', ']');
5a9b54
5a9b54
man_sgml('</TRADEMARK>', "\\u\\s-2TM\\s+2\\d");
5a9b54
5a9b54
man_sgml('<COMMENT>', "[Comment: ");
5a9b54
man_sgml('</COMMENT>', "]");
5a9b54
5a9b54
man_sgml('<QUOTE>', "``");
5a9b54
man_sgml('</QUOTE>', "''");
5a9b54
5a9b54
#man_sgml('<LITERAL>', '"');
5a9b54
#man_sgml('</LITERAL>', '"');
5a9b54
# There doesn't seem to be a good way to represent LITERAL in -man
5a9b54
# ComputerOutput, SGMLTag, Markup are the same thing.
5a9b54
5a9b54
# These create spaces between content in special elements
5a9b54
# without PCDATA content.
5a9b54
man_sgml('</HONORIFIC>', " ");
5a9b54
man_sgml('</FIRSTNAME>', " ");
5a9b54
man_sgml('</SURNAME>', " ");
5a9b54
man_sgml('</LINEAGE>', " ");
5a9b54
man_sgml('</OTHERNAME>', " ");
5a9b54
5a9b54
man_sgml('<AFFILIATION>', "(");
5a9b54
man_sgml('</AFFILIATION>', ") ");
5a9b54
man_sgml('<CONTRIB>', "(");
5a9b54
man_sgml('</CONTRIB>', ") ");
5a9b54
5a9b54
man_sgml('</STREET>', " ");
5a9b54
man_sgml('</POB>', " ");
5a9b54
man_sgml('</POSTCODE>', " ");
5a9b54
man_sgml('</CITY>', " ");
5a9b54
man_sgml('</STATE>', " ");
5a9b54
man_sgml('</COUNTRY>', " ");
5a9b54
man_sgml('</PHONE>', " ");
5a9b54
man_sgml('</FAX>', " ");
5a9b54
man_sgml('</OTHERADDRESS>', " ");
5a9b54
5a9b54
man_sgml('</ALT>', ": ");
5a9b54
man_sgml('<GRAPHIC>', " [GRAPHIC] ");
5a9b54
5a9b54
# No special presentation:
5a9b54
5a9b54
# AUTHORINITIALS
5a9b54
5a9b54
# ABBREV
5a9b54
# ACTION
5a9b54
# ACRONYM
5a9b54
# CITATION
5a9b54
# PHRASE
5a9b54
# QUOTE
5a9b54
# WORDASWORD
5a9b54
5a9b54
# PROMPT
5a9b54
# RETURNVALUE
5a9b54
# TOKEN
5a9b54
5a9b54
# DATABASE
5a9b54
# HARDWARE
5a9b54
# INTERFACE
5a9b54
# MEDIALABEL
5a9b54
5a9b54
5a9b54
########################################################################
5a9b54
#
5a9b54
# Paragraph and paragraph-like elements 
5a9b54
#
5a9b54
########################################################################
5a9b54
5a9b54
sub para_start {
5a9b54
	if($separator eq '' or $separator eq 'full') {
5a9b54
		$separator = '';
5a9b54
		man_output "\n.PP\n";
5a9b54
	} elsif($separator eq 'blank') { 
5a9b54
		man_output "\n\n";
5a9b54
	} elsif($separator eq 'none' ) {
5a9b54
		$_[0]->parent->ext->{'separator'} = 'blank';
5a9b54
		$separator = 'blank';
5a9b54
	}
5a9b54
}
5a9b54
# Actually applies to a few other block elements as well
5a9b54
sub para_end {
5a9b54
	$separator = $_[0]->parent->ext->{'separator'};
5a9b54
	man_output "\n";
5a9b54
}
5a9b54
5a9b54
sgml('<PARA>', \&para_start);
5a9b54
sgml('</PARA>', \&para_end);
5a9b54
sgml('<SIMPARA>', \&para_start);
5a9b54
sgml('</SIMPARA>', \&para_end);
5a9b54
5a9b54
# Nothing special, except maybe FIXME set nobreak.
5a9b54
sgml('<INFORMALEXAMPLE>', \&para_start);
5a9b54
sgml('</INFORMALEXAMPLE>', \&para_end);
5a9b54
5a9b54
5a9b54
########################################################################
5a9b54
#
5a9b54
# Blocks using SS sections
5a9b54
#
5a9b54
########################################################################
5a9b54
5a9b54
# FIXME: We need to consider the effects of SS
5a9b54
# in a hanging tag :(
5a9b54
5a9b54
# Complete with the optional-title dilemma (again).
5a9b54
sgml('<ABSTRACT>', sub {
5a9b54
	$_[0]->ext->{'title'} = 'ABSTRACT';
5a9b54
	output "\n" unless $newline_last++;
5a9b54
	push_output('string');
5a9b54
});
5a9b54
sgml('</ABSTRACT>', sub {
5a9b54
	my $content = pop_output();
5a9b54
	
5a9b54
	# As ABSTRACT is never on the same level as RefSect1,
5a9b54
	# this leaves us with only .SS in terms of -man macros.
5a9b54
	output ".SS \"", uc($_[0]->ext->{'title'}), "\"\n";
5a9b54
5a9b54
	output $content;
5a9b54
	output "\n" unless $newline_last++;
5a9b54
});
5a9b54
5a9b54
5a9b54
5a9b54
# Ah, I needed a break.  Example always has a title.
5a9b54
sgml('<EXAMPLE>', sub { $separator = ''; man_output "\n.SS "});
5a9b54
sgml('</EXAMPLE>', \&para_end);
5a9b54
5a9b54
# Same with sidebar.
5a9b54
sgml('<SIDEBAR>', sub { $separator = ''; man_output "\n.SS "});
5a9b54
sgml('</SIDEBAR>', \&para_end);
5a9b54
5a9b54
sgml('<FORMALPARA>', sub { $separator = ''; man_output "\n.SS "});
5a9b54
sgml('</FORMALPARA>', \&para_end);
5a9b54
5a9b54
sgml('<FIGURE>', sub { $separator = ''; man_output "\n.SS "});
5a9b54
sgml('</FIGURE>', \&para_end);
5a9b54
5a9b54
5a9b54
5a9b54
# NO title.
5a9b54
sgml('<HIGHLIGHTS>', sub { $separator = ''; man_output "\n.SS HIGHLIGHTS\n"});
5a9b54
sgml('</HIGHLIGHTS>', \&para_end);
5a9b54
5a9b54
5a9b54
########################################################################
5a9b54
#
5a9b54
# Indented 'Block' elements 
5a9b54
#
5a9b54
########################################################################
5a9b54
5a9b54
sub indent_block_start
5a9b54
{
5a9b54
	$separator = '';
5a9b54
	man_output "\n.sp\n.RS\n";
5a9b54
}
5a9b54
sub indent_block_end
5a9b54
{
5a9b54
	$separator = $_[0]->parent->ext->{'separator'};
5a9b54
	man_output "\n.RE\n.sp\n";
5a9b54
}
5a9b54
5a9b54
sgml('<ADDRESS>', sub {
5a9b54
	&indent_block_start;
5a9b54
	if($_[0]->attribute('FORMAT')->type eq 'NOTATION'
5a9b54
	   and $_[0]->attribute('FORMAT')->value->name eq 'LINESPECIFIC') {
5a9b54
		&verbatim_start;
5a9b54
	}
5a9b54
});
5a9b54
sgml('</ADDRESS>', sub {
5a9b54
	if($_[0]->attribute('FORMAT')->type eq 'NOTATION'
5a9b54
	   and $_[0]->attribute('FORMAT')->value->name eq 'LINESPECIFIC') {
5a9b54
		&verbatim_end;
5a9b54
	}
5a9b54
	&indent_block_end;
5a9b54
});
5a9b54
	
5a9b54
# This element is almost like an admonition (below),
5a9b54
# only the default title is blank :)
5a9b54
5a9b54
sgml('
', sub {
5a9b54
	$_[0]->ext->{'title'} = ''; 
5a9b54
	&indent_block_start;
5a9b54
	push_output('string');
5a9b54
});
5a9b54
sgml('', sub {
5a9b54
	my $content = pop_output();
5a9b54
5a9b54
	if($_[0]->ext->{'title'}) {
5a9b54
		output ".B \"", $_[0]->ext->{'title'}, ":\"\n";
5a9b54
	}
5a9b54
	
5a9b54
	output $content;
5a9b54
5a9b54
	if($_[0]->ext->{'attribution'}) {
5a9b54
		man_output "\n\n                -- ",
5a9b54
				$_[0]->ext->{'attribution'}, "\n";
5a9b54
	}
5a9b54
	
5a9b54
	&indent_block_end;
5a9b54
});
5a9b54
5a9b54
# Set off admonitions from the rest of the text by indenting.
5a9b54
# FIXME: Need to check if this works inside paragraphs, not enclosing them.
5a9b54
sub admonition_end {
5a9b54
	my $content = pop_output();
5a9b54
5a9b54
	# When the admonition is only one paragraph,
5a9b54
	# it looks nicer if the title was inline.
5a9b54
	my $num_para;
5a9b54
	while ($content =~ /^\.PP/gm) { $num_para++ }
5a9b54
	if($num_para==1) {
5a9b54
		$content =~ s/^\.PP\n//;
5a9b54
	}
5a9b54
	
5a9b54
	output ".B \"" . $_[0]->ext->{'title'} . ":\"\n";
5a9b54
	output $content;
5a9b54
	
5a9b54
	&indent_block_end;
5a9b54
}
5a9b54
5a9b54
sgml('<NOTE>', sub {
5a9b54
	# We can't see right now whether or not there is a TITLE
5a9b54
	# element, so we have to save the output now and add it back
5a9b54
	# at the end of this admonition.
5a9b54
	$_[0]->ext->{'title'} = 'Note';
5a9b54
	
5a9b54
	&indent_block_start;
5a9b54
	
5a9b54
	push_output('string');
5a9b54
});
5a9b54
sgml('</NOTE>', \&admonition_end);
5a9b54
5a9b54
# Same as above.
5a9b54
sgml('<WARNING>', sub { 
5a9b54
	$_[0]->ext->{'title'} = 'Warning'; 
5a9b54
	&indent_block_start;
5a9b54
	push_output('string');
5a9b54
});
5a9b54
sgml('</WARNING>', \&admonition_end);
5a9b54
5a9b54
sgml('<TIP>', sub {
5a9b54
	$_[0]->ext->{'title'} = 'Tip';
5a9b54
	&indent_block_start;
5a9b54
	push_output('string');
5a9b54
});
5a9b54
sgml('</TIP>', \&admonition_end);
5a9b54
sgml('<CAUTION>', sub {
5a9b54
	$_[0]->ext->{'title'} = 'Caution';
5a9b54
	&indent_block_start;
5a9b54
	push_output('string');
5a9b54
});
5a9b54
sgml('</CAUTION>', \&admonition_end);
5a9b54
5a9b54
sgml('<IMPORTANT>', sub {
5a9b54
	$_[0]->ext->{'title'} = 'Important';
5a9b54
	&indent_block_start;
5a9b54
	push_output('string');
5a9b54
});
5a9b54
sgml('</IMPORTANT>', \&admonition_end);
5a9b54
5a9b54
5a9b54
########################################################################
5a9b54
#
5a9b54
# Verbatim displays. 
5a9b54
#
5a9b54
########################################################################
5a9b54
5a9b54
sub verbatim_start {
5a9b54
	$separator = '';
5a9b54
	man_output "\n.sp\n";
5a9b54
	man_output "\n.nf\n" unless $nocollapse_whitespace++;
5a9b54
}
5a9b54
5a9b54
sub verbatim_end {
5a9b54
	man_output "\n.sp\n";
5a9b54
	man_output "\n.fi\n" unless --$nocollapse_whitespace;
5a9b54
	$separator = $_[0]->parent->ext->{'separator'};
5a9b54
}
5a9b54
5a9b54
sgml('<PROGRAMLISTING>', \&verbatim_start); 
5a9b54
sgml('</PROGRAMLISTING>', \&verbatim_end);
5a9b54
5a9b54
sgml('<SCREEN>', \&verbatim_start); 
5a9b54
sgml('</SCREEN>', \&verbatim_end);
5a9b54
5a9b54
sgml('<LITERALLAYOUT>', \&verbatim_start); 
5a9b54
sgml('</LITERALLAYOUT>', \&verbatim_end);
5a9b54
5a9b54
sgml('<SYNOPSIS>', sub {
5a9b54
	my $format = $_[0]->attribute('FORMAT');
5a9b54
5a9b54
	if($format->type eq 'NOTATION'
5a9b54
	   and $format->value->name eq 'LINESPECIFIC')
5a9b54
	{
5a9b54
		&verbatim_start;
5a9b54
	} else {
5a9b54
		$separator = '';
5a9b54
		man_output "\n.sp\n";
5a9b54
	}
5a9b54
});
5a9b54
5a9b54
sgml('</SYNOPSIS>', sub {
5a9b54
	my $format = $_[0]->attribute('FORMAT');
5a9b54
	
5a9b54
	if($format->type eq 'NOTATION'
5a9b54
	   and $format->value->name eq 'LINESPECIFIC')
5a9b54
	{
5a9b54
		&verbatim_end;
5a9b54
	} else {
5a9b54
		man_output "\n";
5a9b54
		$_[0]->parent->ext->{'separator'} = 'full';
5a9b54
		$separator = 'full';
5a9b54
	}
5a9b54
});
5a9b54
5a9b54
5a9b54
########################################################################
5a9b54
#
5a9b54
# Lists
5a9b54
#
5a9b54
########################################################################
5a9b54
5a9b54
# Indent nested lists.
5a9b54
sub list_start {
5a9b54
	man_output "\n.RS\n" if $list_nestlevel++;
5a9b54
}
5a9b54
sub list_end {
5a9b54
	man_output "\n.RE\n" if --$list_nestlevel;
5a9b54
	$_[0]->parent->ext->{'separator'} = 'full';
5a9b54
	$separator = 'full';
5a9b54
}
5a9b54
5a9b54
sgml('<VARIABLELIST>', \&list_start);
5a9b54
sgml('</VARIABLELIST>', \&list_end);
5a9b54
sgml('<ITEMIZEDLIST>', \&list_start);
5a9b54
sgml('</ITEMIZEDLIST>', \&list_end);
5a9b54
sgml('<ORDEREDLIST>', sub { 
5a9b54
	&list_start;
5a9b54
	$_[0]->ext->{'count'} = 1;
5a9b54
});
5a9b54
sgml('</ORDEREDLIST>', \&list_end);
5a9b54
		
5a9b54
# Output content on one line, bolded.
5a9b54
sgml('<TERM>', sub { 
5a9b54
	man_output "\n.TP\n";
5a9b54
	bold_on();
5a9b54
	push_output('string');
5a9b54
});
5a9b54
sgml('</TERM>', sub { 
5a9b54
	my $term = StripString(pop_output());
5a9b54
	$term =~ tr/\n/ /;
5a9b54
	output $term;
5a9b54
	font_off();
5a9b54
	output "\n";
5a9b54
	$newline_last = 1;
5a9b54
});
5a9b54
	
5a9b54
sgml('<LISTITEM>', sub {
5a9b54
	# A bulleted list.
5a9b54
	if($_[0]->in('ITEMIZEDLIST')) {
5a9b54
		man_output "\n.TP 0.2i\n\\(bu\n";
5a9b54
	}
5a9b54
5a9b54
	# Need numbers.
5a9b54
	# Assume Arabic numeration for now.
5a9b54
	elsif($_[0]->in('ORDEREDLIST')) {
5a9b54
		man_output "\n.IP ", $_[0]->parent->ext->{'count'}++, ". \n";
5a9b54
	}
5a9b54
	
5a9b54
	$_[0]->ext->{'separator'} = 'none';
5a9b54
	$separator = 'none';
5a9b54
});
5a9b54
5a9b54
sgml('<SIMPLELIST>', sub {
5a9b54
	$_[0]->ext->{'first_member'} = 1;
5a9b54
});
5a9b54
sgml('<MEMBER>', sub {
5a9b54
	my $parent = $_[0]->parent;
5a9b54
	
5a9b54
	if($parent->attribute('TYPE')->value =~ /Inline/i) {
5a9b54
		if($parent->ext->{'first_member'}) {
5a9b54
			# If this is the first member don't put any commas
5a9b54
			$parent->ext->{'first_member'} = 0;
5a9b54
		} else {
5a9b54
			man_output ", ";
5a9b54
		}
5a9b54
5a9b54
	# We don't really have Horiz rendering, so it's the same
5a9b54
	# as Vert.
5a9b54
	} else {
5a9b54
		man_output "\n\n";
5a9b54
	}
5a9b54
});
5a9b54
5a9b54
# We implement Procedures as indent and lists
5a9b54
5a9b54
sgml('<PROCEDURE>', sub {
5a9b54
	$_[0]->ext->{'count'} = 1;
5a9b54
	&indent_block_start;
5a9b54
});
5a9b54
sgml('</PROCEDURE>', sub {
5a9b54
	&indent_block_end;
5a9b54
	$_[0]->parent->ext->{'separator'} = 'full';
5a9b54
	$separator = 'full';
5a9b54
});
5a9b54
5a9b54
sgml('<STEP>', sub {
5a9b54
	man_output "\n.IP ", $_[0]->parent->ext->{'count'}++, ". \n";
5a9b54
	$_[0]->ext->{'separator'} = 'none';
5a9b54
	$separator = 'none';
5a9b54
});
5a9b54
5a9b54
5a9b54
########################################################################
5a9b54
#
5a9b54
# Linkage, cross references
5a9b54
#
5a9b54
########################################################################
5a9b54
5a9b54
# Print the URL
5a9b54
sgml('</ULINK>', sub {
5a9b54
	man_output ' <URL:', $_[0]->attribute('URL')->value, '>';
5a9b54
});
5a9b54
5a9b54
# If cross reference target is a RefEntry, 
5a9b54
# output CiteRefEntry-style references.
5a9b54
sgml('<XREF>', sub {
5a9b54
	my $id = $_[0]->attribute('LINKEND')->value;
5a9b54
5a9b54
	my $manref = $Refs->get("refentry:$id") || $Refs->get("refsect:$id");
5a9b54
	if(!defined $manref) {
5a9b54
		$blank_xrefs++ if $write_manpages;
5a9b54
		man_output "[XRef to $id]";
5a9b54
		return;
5a9b54
	}
5a9b54
5a9b54
	# Limited ENDTERM support.
5a9b54
	if(defined $_[0]->attribute('ENDTERM')->value) {
5a9b54
		my $endterm = $_[0]->attribute('ENDTERM')->value;
5a9b54
		my $content = $Refs->get("title:$endterm") ||
5a9b54
				$Refs->get("refentrytitle:$endterm");
5a9b54
		man_output $content, ' [';
5a9b54
	}
5a9b54
5a9b54
	# This also displays the XREFLABEL (as bold)...
5a9b54
	# It's not worth the bother to fix it though, there
5a9b54
	# are better tools for this.
5a9b54
	my ($title, $sect) = ($manref =~ /(.*)(\(.*\))/);
5a9b54
	bold_on();
5a9b54
	man_output $title;
5a9b54
	font_off();
5a9b54
	man_output $sect;
5a9b54
5a9b54
	if(defined $_[0]->attribute('ENDTERM')->value) {
5a9b54
		man_output ']';
5a9b54
	}
5a9b54
});
5a9b54
5a9b54
# Anchor
5a9b54
5a9b54
########################################################################
5a9b54
#
5a9b54
# SDATA 
5a9b54
#
5a9b54
########################################################################
5a9b54
5a9b54
man_sgml('|[lt    ]|', '<');
5a9b54
man_sgml('|[equals]|', '=');
5a9b54
man_sgml('|[gt    ]|', '>');
5a9b54
man_sgml('|[plus  ]|', '\(pl');
5a9b54
man_sgml('|[dollar]|', '$');
5a9b54
man_sgml('|[num   ]|', '#');
5a9b54
man_sgml('|[percnt]|', '%');
5a9b54
man_sgml('|[amp   ]|', '&';;
5a9b54
man_sgml('|[commat]|', '@');
5a9b54
man_sgml('|[lsqb  ]|', '[');
5a9b54
man_sgml('|[bsol  ]|', '\e');
5a9b54
man_sgml('|[rsqb  ]|', ']');
5a9b54
man_sgml('|[lcub  ]|', '{');
5a9b54
man_sgml('|[verbar]|', '\(or');
5a9b54
man_sgml('|[rcub  ]|', '}');
5a9b54
man_sgml('|[excl  ]|', '!');
5a9b54
man_sgml('|[quot  ]|', '"');
5a9b54
man_sgml('|[apos  ]|', '\\&\'');
5a9b54
man_sgml('|[lpar  ]|', '(');
5a9b54
man_sgml('|[rpar  ]|', ')');
5a9b54
man_sgml('|[comma ]|', ',');
5a9b54
man_sgml('|[lowbar]|', '_');
5a9b54
man_sgml('|[period]|', '.');
5a9b54
man_sgml('|[sol   ]|', '/');
5a9b54
man_sgml('|[colon ]|', ':');
5a9b54
man_sgml('|[semi  ]|', ';');
5a9b54
man_sgml('|[quest ]|', '?');
5a9b54
man_sgml('|[grave ]|', '`');
5a9b54
man_sgml('|[tilde ]|', '~');
5a9b54
man_sgml('|[half  ]|', '\(12');
5a9b54
man_sgml('|[frac12]|', '\(12');
5a9b54
man_sgml('|[frac14]|', '\(14');
5a9b54
man_sgml('|[frac34]|', '\(34');
5a9b54
man_sgml('|[frac18]|', '1/8');
5a9b54
man_sgml('|[frac38]|', '3/8');
5a9b54
man_sgml('|[frac58]|', '5/8');
5a9b54
man_sgml('|[frac78]|', '7/8');
5a9b54
man_sgml('|[sup1  ]|', '\u1\l');
5a9b54
man_sgml('|[sup2  ]|', '\u2\l');
5a9b54
man_sgml('|[sup3  ]|', '\u3\l');
5a9b54
man_sgml('|[plusmn]|', '\(+-');
5a9b54
man_sgml('|[divide]|', '\(di');
5a9b54
man_sgml('|[times ]|', '\(ti');
5a9b54
man_sgml('|[pound ]|', '#');
5a9b54
man_sgml('|[cent  ]|', '\(ct');
5a9b54
man_sgml('|[yen   ]|', 'yen');
5a9b54
man_sgml('|[ast   ]|', '*');
5a9b54
man_sgml('|[horbar]|', '_');
5a9b54
man_sgml('|[micro ]|', '\(*m');
5a9b54
man_sgml('|[ohm   ]|', '\(*W');
5a9b54
man_sgml('|[deg   ]|', '\(de');
5a9b54
man_sgml('|[sect  ]|', '\(sc');
5a9b54
man_sgml('|[larr  ]|', '\(<-');
5a9b54
man_sgml('|[rarr  ]|', '\(->');
5a9b54
man_sgml('|[uarr  ]|', '\(ua');
5a9b54
man_sgml('|[darr  ]|', '\(da');
5a9b54
man_sgml('|[copy  ]|', '\(co');
5a9b54
man_sgml('|[reg   ]|', '\(rg');
5a9b54
man_sgml('|[trade ]|', '\(tm');
5a9b54
man_sgml('|[brvbar]|', '|');
5a9b54
man_sgml('|[not   ]|', '\(no');
5a9b54
man_sgml('|[hyphen]|', '\-');
5a9b54
man_sgml('|[laquo ]|', '<<');
5a9b54
man_sgml('|[raquo ]|', '>>');
5a9b54
man_sgml('|[lsquo ]|', '`');
5a9b54
man_sgml('|[rsquo ]|', '\&\'');
5a9b54
man_sgml('|[ldquo ]|', '"');
5a9b54
man_sgml('|[rdquo ]|', '"');
5a9b54
man_sgml('|[nbsp  ]|', '\ ');
5a9b54
man_sgml('|[shy   ]|', '\%');
5a9b54
man_sgml('|[emsp  ]|', '\ \ ');
5a9b54
man_sgml('|[ensp  ]|', '\ ');
5a9b54
man_sgml('|[emsp3 ]|', '\ ');
5a9b54
man_sgml('|[emsp4 ]|', '\ ');
5a9b54
man_sgml('|[numsp ]|', '\0');
5a9b54
man_sgml('|[puncsp]|', '\|');
5a9b54
man_sgml('|[thinsp]|', '\!');
5a9b54
man_sgml('|[hairsp]|', '\\^');
5a9b54
man_sgml('|[mdash ]|', '\(em');
5a9b54
man_sgml('|[ndash ]|', '-');
5a9b54
man_sgml('|[dash  ]|', '-');
5a9b54
man_sgml('|[blank ]|', '\ ');
5a9b54
man_sgml('|[hellip]|', '\&...');
5a9b54
man_sgml('|[nldr  ]|', '\&..');
5a9b54
man_sgml('|[frac13]|', '1/3');
5a9b54
man_sgml('|[frac23]|', '2/3');
5a9b54
man_sgml('|[frac15]|', '1/5');
5a9b54
man_sgml('|[frac25]|', '2/5');
5a9b54
man_sgml('|[frac35]|', '3/5');
5a9b54
man_sgml('|[frac45]|', '4/5');
5a9b54
man_sgml('|[frac16]|', '1/6');
5a9b54
man_sgml('|[frac56]|', '5/6');
5a9b54
man_sgml('|[cir   ]|', '\(ci');
5a9b54
man_sgml('|[squ   ]|', '\(sq');
5a9b54
man_sgml('|[star  ]|', '\(**');
5a9b54
man_sgml('|[bull  ]|', '\(bu');
5a9b54
man_sgml('|[dagger]|', '\(dg');
5a9b54
man_sgml('|[Dagger]|', '\(dd');
5a9b54
man_sgml('|[caret ]|', '\^');
5a9b54
man_sgml('|[lsquor]|', '`');
5a9b54
man_sgml('|[ldquor]|', '``');
5a9b54
man_sgml('|[fflig ]|', '\(ff');
5a9b54
man_sgml('|[filig ]|', '\(fi');
5a9b54
man_sgml('|[ffilig]|', '\(Fi');
5a9b54
man_sgml('|[ffllig]|', '\(Fl');
5a9b54
man_sgml('|[fllig ]|', '\(fl');
5a9b54
man_sgml('|[rdquor]|', '\&\'\'');
5a9b54
man_sgml('|[rsquor]|', '\&\'');
5a9b54
man_sgml('|[vellip]|', '\&...');
5a9b54
man_sgml('|[aacute]|', '\(a\'');
5a9b54
man_sgml('|[Aacute]|', '\(A\'');
5a9b54
man_sgml('|[acirc ]|', '\(a^');
5a9b54
man_sgml('|[Acirc ]|', '\(A^');
5a9b54
man_sgml('|[agrave]|', '\(a`');
5a9b54
man_sgml('|[Agrave]|', '\(A`');
5a9b54
man_sgml('|[auml  ]|', '\(a:');
5a9b54
man_sgml('|[aelig ]|', '\(ae');
5a9b54
man_sgml('|[AElig ]|', '\(AE');
5a9b54
man_sgml('|[eacute]|', '\(e\'');
5a9b54
man_sgml('|[Eacute]|', '\(E\'');
5a9b54
man_sgml('|[egrave]|', '\(e`');
5a9b54
man_sgml('|[Egrave]|', '\(E`');
5a9b54
man_sgml('|[iacute]|', '\(i\'');
5a9b54
man_sgml('|[Iacute]|', '\(I\'');
5a9b54
man_sgml('|[igrave]|', '\(i`');
5a9b54
man_sgml('|[Igrave]|', '\(I`');
5a9b54
man_sgml('|[ntilde]|', '\(n~');
5a9b54
man_sgml('|[Ntilde]|', '\(N~');
5a9b54
man_sgml('|[oacute]|', '\(o\'');
5a9b54
man_sgml('|[Oacute]|', '\(O\'');
5a9b54
man_sgml('|[ograve]|', '\(o`');
5a9b54
man_sgml('|[Ograve]|', '\(O`');
5a9b54
man_sgml('|[oslash]|', '\(o/');
5a9b54
man_sgml('|[Oslash]|', '\(O/');
5a9b54
man_sgml('|[szlig ]|', '\(ss');
5a9b54
man_sgml('|[thorn ]|', '\(th');
5a9b54
man_sgml('|[uacute]|', '\(u\'');
5a9b54
man_sgml('|[Uacute]|', '\(U\'');
5a9b54
man_sgml('|[ugrave]|', '\(u`');
5a9b54
man_sgml('|[Ugrave]|', '\(U`');
5a9b54
man_sgml('|[aogon ]|', '\(ao');
5a9b54
man_sgml('|[agr   ]|', '\(*a');
5a9b54
man_sgml('|[Agr   ]|', '\(*A');
5a9b54
man_sgml('|[bgr   ]|', '\(*b');
5a9b54
man_sgml('|[Bgr   ]|', '\(*B');
5a9b54
man_sgml('|[ggr   ]|', '\(*g');
5a9b54
man_sgml('|[Ggr   ]|', '\(*G');
5a9b54
man_sgml('|[dgr   ]|', '\(*d');
5a9b54
man_sgml('|[Dgr   ]|', '\(*D');
5a9b54
man_sgml('|[egr   ]|', '\(*e');
5a9b54
man_sgml('|[Egr   ]|', '\(*E');
5a9b54
man_sgml('|[zgr   ]|', '\(*z');
5a9b54
man_sgml('|[Zgr   ]|', '\(*Z');
5a9b54
man_sgml('|[eegr  ]|', '\(*y');
5a9b54
man_sgml('|[EEgr  ]|', '\(*Y');
5a9b54
man_sgml('|[thgr  ]|', '\(*h');
5a9b54
man_sgml('|[THgr  ]|', '\(*H');
5a9b54
man_sgml('|[igr   ]|', '\(*i');
5a9b54
man_sgml('|[Igr   ]|', '\(*I');
5a9b54
man_sgml('|[kgr   ]|', '\(*k');
5a9b54
man_sgml('|[Kgr   ]|', '\(*K');
5a9b54
man_sgml('|[lgr   ]|', '\(*l');
5a9b54
man_sgml('|[Lgr   ]|', '\(*L');
5a9b54
man_sgml('|[mgr   ]|', '\(*m');
5a9b54
man_sgml('|[Mgr   ]|', '\(*M');
5a9b54
man_sgml('|[ngr   ]|', '\(*n');
5a9b54
man_sgml('|[Ngr   ]|', '\(*N');
5a9b54
man_sgml('|[xgr   ]|', '\(*c');
5a9b54
man_sgml('|[Xgr   ]|', '\(*C');
5a9b54
man_sgml('|[ogr   ]|', '\(*o');
5a9b54
man_sgml('|[Ogr   ]|', '\(*O');
5a9b54
man_sgml('|[pgr   ]|', '\(*p');
5a9b54
man_sgml('|[Pgr   ]|', '\(*P');
5a9b54
man_sgml('|[rgr   ]|', '\(*r');
5a9b54
man_sgml('|[Rgr   ]|', '\(*R');
5a9b54
man_sgml('|[sgr   ]|', '\(*s');
5a9b54
man_sgml('|[Sgr   ]|', '\(*S');
5a9b54
man_sgml('|[sfgr  ]|', '\(ts');
5a9b54
man_sgml('|[tgr   ]|', '\(*t');
5a9b54
man_sgml('|[Tgr   ]|', '\(*T');
5a9b54
man_sgml('|[ugr   ]|', '\(*u');
5a9b54
man_sgml('|[Ugr   ]|', '\(*U');
5a9b54
man_sgml('|[phgr  ]|', '\(*f');
5a9b54
man_sgml('|[PHgr  ]|', '\(*F');
5a9b54
man_sgml('|[khgr  ]|', '\(*x');
5a9b54
man_sgml('|[KHgr  ]|', '\(*X');
5a9b54
man_sgml('|[psgr  ]|', '\(*q');
5a9b54
man_sgml('|[PSgr  ]|', '\(*Q');
5a9b54
man_sgml('|[ohgr  ]|', '\(*w');
5a9b54
man_sgml('|[OHgr  ]|', '\(*W');
5a9b54
man_sgml('|[alpha ]|', '\(*a');
5a9b54
man_sgml('|[beta  ]|', '\(*b');
5a9b54
man_sgml('|[gamma ]|', '\(*g');
5a9b54
man_sgml('|[Gamma ]|', '\(*G');
5a9b54
man_sgml('|[delta ]|', '\(*d');
5a9b54
man_sgml('|[Delta ]|', '\(*D');
5a9b54
man_sgml('|[epsi  ]|', '\(*e');
5a9b54
man_sgml('|[epsis ]|', '\(*e');
5a9b54
man_sgml('|[zeta  ]|', '\(*z');
5a9b54
man_sgml('|[eta   ]|', '\(*y');
5a9b54
man_sgml('|[thetas]|', '\(*h');
5a9b54
man_sgml('|[Theta ]|', '\(*H');
5a9b54
man_sgml('|[iota  ]|', '\(*i');
5a9b54
man_sgml('|[kappa ]|', '\(*k');
5a9b54
man_sgml('|[lambda]|', '\(*l');
5a9b54
man_sgml('|[Lambda]|', '\(*L');
5a9b54
man_sgml('|[mu    ]|', '\(*m');
5a9b54
man_sgml('|[nu    ]|', '\(*n');
5a9b54
man_sgml('|[xi    ]|', '\(*c');
5a9b54
man_sgml('|[Xi    ]|', '\(*C');
5a9b54
man_sgml('|[pi    ]|', '\(*p');
5a9b54
man_sgml('|[Pi    ]|', '\(*P');
5a9b54
man_sgml('|[rho   ]|', '\(*r');
5a9b54
man_sgml('|[sigma ]|', '\(*s');
5a9b54
man_sgml('|[Sigma ]|', '\(*S');
5a9b54
man_sgml('|[tau   ]|', '\(*t');
5a9b54
man_sgml('|[upsi  ]|', '\(*u');
5a9b54
man_sgml('|[Upsi  ]|', '\(*U');
5a9b54
man_sgml('|[phis  ]|', '\(*f');
5a9b54
man_sgml('|[Phi   ]|', '\(*F');
5a9b54
man_sgml('|[chi   ]|', '\(*x');
5a9b54
man_sgml('|[psi   ]|', '\(*q');
5a9b54
man_sgml('|[Psi   ]|', '\(*X');
5a9b54
man_sgml('|[omega ]|', '\(*w');
5a9b54
man_sgml('|[Omega ]|', '\(*W');
5a9b54
man_sgml('|[ap    ]|', '\(ap');
5a9b54
man_sgml('|[equiv ]|', '\(==');
5a9b54
man_sgml('|[ge    ]|', '\(>=');
5a9b54
man_sgml('|[infin ]|', '\(if');
5a9b54
man_sgml('|[isin  ]|', '\(sb');
5a9b54
man_sgml('|[le    ]|', '\(<=');
5a9b54
man_sgml('|[minus ]|', '\(mi');
5a9b54
man_sgml('|[ne    ]|', '\(!=');
5a9b54
man_sgml('|[prop  ]|', '\(pt');
5a9b54
man_sgml('|[square]|', '\(sq');
5a9b54
man_sgml('|[sub   ]|', '\(sb');
5a9b54
man_sgml('|[sube  ]|', '\(ib');
5a9b54
man_sgml('|[sup   ]|', '\(sp');
5a9b54
man_sgml('|[supe  ]|', '\(ip');
5a9b54
man_sgml('|[acute ]|', '\&\'');
5a9b54
man_sgml('|[breve ]|', '\(be');
5a9b54
man_sgml('|[caron ]|', '\(hc');
5a9b54
man_sgml('|[cedil ]|', '\(cd');
5a9b54
man_sgml('|[dot   ]|', '\(dt');
5a9b54
man_sgml('|[macr  ]|', '\(ma');
5a9b54
man_sgml('|[ogon  ]|', '\(og');
5a9b54
man_sgml('|[ring  ]|', '\(ri');
5a9b54
man_sgml('|[uml   ]|', '\(..');
5a9b54
5a9b54
sgml('sdata',sub {
5a9b54
	my ($element, $event) = @_;
5a9b54
	my ($file, $line) = ($event->file, $event->line);
5a9b54
	man_output "|[", $_[0], "]|";
5a9b54
	warn "Warning: unrecognized SDATA '$_[0]'"
5a9b54
	     . ($file && $line ? " in $file on line $line" : "")
5a9b54
	     . ": please add definition to docbook2man-spec.pl\n";
5a9b54
});
5a9b54
5a9b54
#
5a9b54
# Default handlers (uncomment these if needed).  Right now, these are set
5a9b54
# up to gag on any unrecognised elements, sdata, processing-instructions,
5a9b54
# or entities.
5a9b54
#
5a9b54
# sgml('start_element',sub { die "Unknown element: " . $_[0]->name; });
5a9b54
# sgml('end_element','');
5a9b54
5a9b54
# This is for weeding out and escaping certain characters.
5a9b54
# This looks like it's inefficient since it's done on every line, but
5a9b54
# in reality, SGMLSpm and sgmlspl parsing ESIS takes _much_ longer.
5a9b54
5a9b54
sgml('cdata', sub
5a9b54
{ 
5a9b54
	if(!$write_manpages) { return; }
5a9b54
	elsif($raw_cdata) { output $_[0]; return; }
5a9b54
5a9b54
	if($separator eq 'full') {
5a9b54
		output "\n" unless $newline_last++;
5a9b54
		output ".PP\n";
5a9b54
		$separator = '';
5a9b54
	}
5a9b54
	
5a9b54
	# Escape backslashes
5a9b54
	$_[0] =~ s/\\/\\\\/g;
5a9b54
5a9b54
  # Escape dots and single quotes in column 1
5a9b54
	$_[0] =~ s/^[ \t]*\./\\\&\./;
5a9b54
	$_[0] =~ s/^[ \t]*\'/\\\&\'/;
5a9b54
5a9b54
5a9b54
	# In non-'pre'-type elements:
5a9b54
	if(!$nocollapse_whitespace) {
5a9b54
		# Change tabs to spaces
5a9b54
		$_[0] =~ tr/\t / /s;
5a9b54
5a9b54
		# Do not allow indents at beginning of line
5a9b54
		# groff chokes on that.
5a9b54
		if($newline_last) { 
5a9b54
			$_[0] =~ s/^ //;
5a9b54
5a9b54
			# If the line is all blank, don't do anything.
5a9b54
			if($_[0] eq '') { return; }
5a9b54
			
5a9b54
			$_[0] =~ s/^\./\\\&\./;
5a9b54
	
5a9b54
			# Argh... roff doesn't like ' for some unknown reason 
5a9b54
			$_[0] =~ s/^\'/\\\&\'/;
5a9b54
		}
5a9b54
	}
5a9b54
5a9b54
	$newline_last = 0;
5a9b54
5a9b54
	output $_[0];
5a9b54
});
5a9b54
5a9b54
5a9b54
# When in whitespace-collapsing mode, we disallow consecutive newlines.
5a9b54
5a9b54
sgml('re', sub
5a9b54
{
5a9b54
	if($nocollapse_whitespace || !$newline_last) {
5a9b54
		output "\n";
5a9b54
	}
5a9b54
5a9b54
	$newline_last = 1;
5a9b54
});
5a9b54
5a9b54
sgml('pi', sub {});
5a9b54
sgml('entity',sub { die "Unknown external entity: " . $_[0]->name; });
5a9b54
sgml('start_subdoc',sub { die "Unknown subdoc entity: " . $_[0]->name; });
5a9b54
sgml('end_subdoc',sub{});
5a9b54
sgml('conforming',sub{});
5a9b54
5a9b54
1;
5a9b54