3 docbook2man-spec - convert DocBook RefEntries to Unix manpages
7 The SGMLSpm package from CPAN. This contains the sgmlspl script which
8 is used to grok this file. Use it like this:
10 nsgmls some-docbook-document.sgml | sgmlspl docbook2man-spec.pl
14 This is a sgmlspl spec file that produces Unix-style
15 manpages from RefEntry markup.
17 See the accompanying RefEntry man page for 'plain new' documentation. :)
21 Trying docbook2man on non-DocBook or non-conformant SGML results in
22 undefined behavior. :-)
24 This program is a slow, dodgy Perl script.
26 This program does not come close to supporting all the possible markup
27 in DocBook, and will produce wrong output in some cases with supported
32 Add new element handling and fix existing handling. Be robust.
33 Produce cleanest, readable man output as possible (unlike some
34 other converters). Follow Linux man(7) convention.
35 If this results in added logic in this script,
36 that's okay. The code should still be reasonably organized.
38 Make it faster. If Perl sucks port it to another language.
42 Copyright (C) 1998-1999 Steve Cheng <steve@ggi-project.org>
44 This program is free software; you can redistribute it and/or modify it
45 under the terms of the GNU General Public License as published by the Free
46 Software Foundation; either version 2, or (at your option) any later
49 You should have received a copy of the GNU General Public License along with
50 this program; see the file COPYING. If not, please write to the Free
51 Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
55 # $Id: docbook2man-spec.pl,v 1.10 2003/06/10 08:30:30 twaugh Exp $
57 use SGMLS; # Use the SGMLS package.
58 use SGMLS::Output; # Use stack-based output.
61 ########################################################################
62 # SGMLSPL script produced automatically by the script sgmlspl.pl
64 # Document Type: any, but processes only RefEntries
66 ########################################################################
73 $raw_cdata = 1; # Makes it a bit faster.
76 open(LINKSFILE, ">manpage.links");
78 $Refs = new SGMLS::Refs("manpage.refs");
83 print STDERR "Warning: output contains unresolved XRefs\n";
90 ########################################################################
94 ########################################################################
96 # Our own version of sgml() and output() to allow simple string output
97 # to play well with roff's stupid whitespace rules.
101 if(ref($_[1]) eq 'CODE') {
110 # \n at the beginning means start at beginning of line
112 $sub = 'sub { output "\n" unless $newline_last++; ';
114 sgml($_[0], eval('sub { output "\n" unless $newline_last++; }'));
115 } elsif($s =~ /\n$/) {
116 sgml($_[0], eval("sub { output \"\\n\" unless \$newline_last++; output '$s'; }"));
118 sgml($_[0], eval("sub { output \"\\n\" unless \$newline_last; output '$s'; \$newline_last = 0; }"));
122 sgml($_[0], eval("sub { output '$s'; \$newline_last = 1; }"));
124 sgml($_[0], eval("sub { output '$s'; \$newline_last = 0; }"));
133 output "\n" unless $newline_last++;
141 $newline_last = (pop(@_) =~ /\n$/);
143 $newline_last = ($_ =~ /\n$/)
147 # Fold lines into one, quote some characters
155 # Change tabs to spaces
158 # Trim whitespace from beginning and end.
168 push_output('string');
173 # If the last font is also bold, don't change anything.
174 # Basically this is to just get more readable man output.
175 if($fontstack[$#fontstack] ne 'bold') {
181 push(@fontstack, 'bold');
186 # If the last font is also italic, don't change anything.
187 if($fontstack[$#fontstack] ne 'italic') {
193 push(@fontstack, 'italic');
198 my $thisfont = pop(@fontstack);
199 my $lastfont = $fontstack[$#fontstack];
201 # Only output font change if it is different
202 if($thisfont ne $lastfont) {
203 if($raw_cdata) { return; }
204 elsif($lastfont eq 'bold') { output '\fB'; }
205 elsif($lastfont eq 'italic') { output '\fI'; }
206 else { output '\fR'; }
217 ########################################################################
221 ########################################################################
223 sgml('<REFENTRY>', sub {
224 # This will be overwritten at end of REFMETA, when we know the name of the page.
227 $write_manpages = 1; # Currently writing manpage.
229 $nocollapse_whitespace = 0; # Current whitespace collapse counter.
230 $newline_last = 1; # At beginning of line?
231 # Just a bit of warning, you will see this variable manipulated
232 # manually a lot. It makes the code harder to follow but it
233 # saves you from having to worry about collapsing at the end of
234 # parse, stopping at verbatims, etc.
235 $raw_cdata = 0; # Instructs certain output functions to
236 # leave CDATA alone, so we can assign
237 # it to a string and process it, etc.
238 @fontstack = (); # Fonts being activated.
240 $manpage_title = ''; # Needed for indexing.
246 $list_nestlevel = 0; # Indent certain nested content.
248 # check refentry's language
249 if(defined($_[0]->attribute('LANG')->value)) {
250 $manpage_lang = $_[0]->attribute('LANG')->value;
256 sgml('</REFENTRY>', sub {
266 sgml('</REFMETA>', sub {
268 push_output('file', "$manpage_title.$manpage_lang.$manpage_sect");
270 push_output('file', "$manpage_title.$manpage_sect");
273 output <<_END_BANNER;
274 .\\" This manpage has been automatically generated by docbook2man
275 .\\" from a DocBook document. This tool can be found at:
276 .\\" <http://shell.ipoline.com/~elmert/comp/docbook2X/>
277 .\\" Please send any bug reports, improvements, comments, patches,
278 .\\" etc. to Steve Cheng <steve\@ggi-project.org>.
281 my $manpage_date = `date "+%d %B %Y"`;
285 # If the title is not mixed-case, convention says to
286 # uppercase the whole title. (The canonical title is
288 if($manpage_title =~ /[A-Z]/) {
289 output fold_string($manpage_title);
291 output uc(fold_string($manpage_title));
294 output '" "', fold_string($manpage_sect),
295 '" "', fold_string(`date "+%d %B %Y"`),
296 '" "', $manpage_misc,
297 '" "', $manpage_manual,
302 # References to this RefEntry.
303 my $id = $_[0]->parent->attribute('ID')->value;
305 # The 'package name' part of the section should
306 # not be used when citing it.
307 my ($sectnum) = ($manpage_sect =~ /([0-9]*)/);
309 if($_[0]->parent->attribute('XREFLABEL')->value eq '') {
310 $Refs->put("refentry:$id", "$manpage_title($sectnum)");
312 $Refs->put("refentry:$id",
313 $_[0]->parent->attribute('XREFLABEL')->value .
319 sgml('<REFENTRYTITLE>', sub {
320 if($_[0]->in('REFMETA')) {
323 # Manpage citations are in bold.
327 sgml('</REFENTRYTITLE>', sub {
328 if($_[0]->in('REFMETA')) {
330 $manpage_title = pop_output();
335 sgml('<MANVOLNUM>', sub {
336 if($_[0]->in('REFMETA')) {
339 # Manpage citations use ().
343 sgml('</MANVOLNUM>', sub {
344 if($_[0]->in('REFMETA')) {
346 $manpage_sect = pop_output();
351 sgml('<REFMISCINFO>', \&save_cdata);
352 sgml('</REFMISCINFO>', sub {
354 $manpage_misc = fold_string(pop_output());
359 man_sgml('<REFNAMEDIV>', sub {
360 my %words = qw( fr NOM es NOMBRE de NAME );
361 if (defined($_[0]->attribute('LANG')->value)) {
362 my $id = $_[0]->attribute('LANG')->value;
363 my $ad = $words{$id};
364 output("\n.SH $ad\n");}
365 else {output("\n.SH NAME\n");}
368 sgml('<REFNAME>', \&save_cdata);
369 sgml('</REFNAME>', sub {
371 push(@manpage_names, pop_output());
374 sgml('<REFPURPOSE>', \&save_cdata);
375 sgml('</REFPURPOSE>', sub {
377 my $manpage_purpose = fold_string(pop_output());
379 for(my $i = 0; $i < $#manpage_names; $i++) {
380 output fold_string($manpage_names[$i]), ', ';
383 output fold_string($manpage_names[$#manpage_names]);
384 output " \\- $manpage_purpose\n";
388 foreach(@manpage_names) {
389 # Don't link to itself
390 if($_ ne $manpage_title) {
391 print LINKSFILE "$manpage_title.$manpage_sect $_.$manpage_sect\n";
396 man_sgml('<REFCLASS>', "\n.sp\n");
404 ########################################################################
406 # SYNOPSIS section and synopses
408 ########################################################################
410 man_sgml('<REFSYNOPSISDIV>', "\n.SH SYNOPSIS\n");
411 man_sgml('</REFSYNOPSISDIV>', "\n");
413 ## FIXME! Must be made into block elements!!
414 #sgml('<FUNCSYNOPSIS>', \&bold_on);
415 #sgml('</FUNCSYNOPSIS>', \&font_off);
416 #sgml('<CMDSYNOPSIS>', \&bold_on);
417 #sgml('</CMDSYNOPSIS>', \&font_off);
419 man_sgml('<FUNCSYNOPSIS>', sub {
420 man_output("\n.sp\n");
423 man_sgml('</FUNCSYNOPSIS>', sub {
428 man_sgml('<CMDSYNOPSIS>', "\n\n");
429 man_sgml('</CMDSYNOPSIS>', "\n\n");
431 man_sgml('<FUNCPROTOTYPE>', "\n.sp\n");
433 # Arguments to functions. This is C convention.
436 if($_[0]->parent->ext->{'inparams'}) {
440 $_[0]->parent->ext->{'inparams'} = 1;
443 man_sgml('<PARAMDEF>', \¶mdef);
444 man_sgml('</FUNCPROTOTYPE>', ");\n");
445 man_sgml('<VOID>', "(void");
446 man_sgml('<VARARGS>', "(...");
452 if(not $_[0]->parent->in('TERM')) {
453 if($_[0]->attribute('CHOICE')->value =~ /opt/i) {
455 } elsif($_[0]->attribute('CHOICE')->value =~ /req/i) {
459 $_[0]->ext->{'count'} = 1;
463 if($_[0]->attribute('REP')->value =~ /^Repeat/i) {
468 if(not $_[0]->parent->in('TERM')) {
469 if($_[0]->attribute('CHOICE')->value =~ /opt/i) {
471 } elsif($_[0]->attribute('CHOICE')->value =~ /req/i) {
479 # my $choice = $_[0]->attribute('CHOICE')->value;
481 # The content model for CmdSynopsis doesn't include #PCDATA,
482 # so we won't see any of the whitespace in the source file,
483 # so we have to add it after each component.
486 if($_[0]->in('GROUP')) {
487 output '| ' if $_[0]->parent->ext->{'count'} > 1;
488 $_[0]->parent->ext->{'count'}++;
489 } elsif($_[0]->attribute('CHOICE')->value =~ /opt/i) {
497 if($_[0]->attribute('REP')->value =~ /^Repeat/i) {
502 if($_[0]->attribute('CHOICE')->value =~ /opt/i and
503 not $_[0]->in('GROUP')) {
508 sgml('<ARG>', \&arg_start);
509 sgml('</ARG>', \&arg_end);
510 sgml('<GROUP>', \&group_start);
511 sgml('</GROUP>', \&group_end);
513 sgml('<OPTION>', \&bold_on);
514 sgml('</OPTION>', \&font_off);
516 man_sgml('<SBR>', "\n ");
519 ########################################################################
523 ########################################################################
525 # The name of the section is handled by TITLE. This just sets
526 # up the roff markup.
527 man_sgml('<REFSECT1>', "\n.SH ");
528 man_sgml('<REFSECT2>', "\n.SS ");
529 man_sgml('<REFSECT3>', "\n.SS ");
532 ########################################################################
536 ########################################################################
538 sgml('<TITLE>', sub {
539 if($_[0]->in('REFERENCE') or $_[0]->in('BOOK')) {
544 sgml('</TITLE>', sub {
545 my $title = fold_string(pop_output());
548 if($_[0]->in('REFERENCE') or $_[0]->in('BOOK')) {
549 # We use TITLE of enclosing Reference or Book as manual name
550 $manpage_manual = $title;
553 elsif(exists $_[0]->parent->ext->{'title'}) {
554 # By far the easiest case. Just fold the string as
555 # above, and then set the parent element's variable.
556 $_[0]->parent->ext->{'title'} = $title;
559 # If the parent element's handlers are lazy,
560 # output the folded string for them :)
561 # We assume they want uppercase and a newline.
562 output '"', uc($title), "\"\n";
567 sgml('<ATTRIBUTION>', sub { push_output('string') });
568 sgml('</ATTRIBUTION>', sub { $_[0]->parent->ext->{'attribution'} = pop_output(); });
572 sgml('<DOCINFO>', sub { push_output('nul'); });
573 sgml('</DOCINFO>', sub { pop_output(); });
574 sgml('<REFSECT1INFO>', sub { push_output('nul'); });
575 sgml('</REFSECT1INFO>', sub { pop_output(); });
576 sgml('<REFSECT2INFO>', sub { push_output('nul'); });
577 sgml('</REFSECT2INFO>', sub { pop_output(); });
578 sgml('<REFSECT3INFO>', sub { push_output('nul'); });
579 sgml('</REFSECT3INFO>', sub { pop_output(); });
581 sgml('<INDEXTERM>', sub { push_output('nul'); });
582 sgml('</INDEXTERM>', sub { pop_output(); });
585 ########################################################################
587 # Set bold on enclosed content
589 ########################################################################
591 sgml('<APPLICATION>', \&bold_on); sgml('</APPLICATION>', \&font_off);
593 sgml('<CLASSNAME>', \&bold_on); sgml('</CLASSNAME>', \&font_off);
594 sgml('<STRUCTNANE>', \&bold_on); sgml('</STRUCTNAME>', \&font_off);
595 sgml('<STRUCTFIELD>', \&bold_on); sgml('</STRUCTFIELD>', \&font_off);
596 sgml('<SYMBOL>', \&bold_on); sgml('</SYMBOL>', \&font_off);
597 sgml('<TYPE>', \&bold_on); sgml('</TYPE>', \&font_off);
599 sgml('<ENVAR>', \&bold_on); sgml('</ENVAR>', \&font_off);
601 sgml('<FUNCTION>', \&bold_on); sgml('</FUNCTION>', \&font_off);
603 sgml('<EMPHASIS>', \&bold_on); sgml('</EMPHASIS>', \&font_off);
605 sgml('<ERRORNAME>', \&bold_on); sgml('</ERRORNAME>', \&font_off);
608 sgml('<COMMAND>', \&bold_on); sgml('</COMMAND>', \&font_off);
610 sgml('<GUIBUTTON>', \&bold_on); sgml('</GUIBUTTON>', \&font_off);
611 sgml('<GUIICON>', \&bold_on); sgml('</GUIICON>', \&font_off);
619 sgml('<ACCEL>', \&bold_on); sgml('</ACCEL>', \&font_off);
620 sgml('<KEYCAP>', \&bold_on); sgml('</KEYCAP>', \&font_off);
621 sgml('<KEYSYM>', \&bold_on); sgml('</KEYSYM>', \&font_off);
626 sgml('<USERINPUT>', \&bold_on); sgml('</USERINPUT>', \&font_off);
628 sgml('<INTERFACEDEFINITION>', \&bold_on);
629 sgml('</INTERFACEDEFINITION>', \&font_off);
631 # May need to look at the CLASS
632 sgml('<SYSTEMITEM>', \&bold_on);
633 sgml('</SYSTEMITEM>', \&font_off);
639 ########################################################################
641 # Set italic on enclosed content
643 ########################################################################
645 sgml('<FIRSTTERM>', \&italic_on); sgml('</FIRSTTERM>', \&font_off);
647 sgml('<FILENAME>', \&italic_on); sgml('</FILENAME>', \&font_off);
648 sgml('<PARAMETER>', \&italic_on); sgml('</PARAMETER>', \&font_off);
649 sgml('<PROPERTY>', \&italic_on); sgml('</PROPERTY>', \&font_off);
651 sgml('<REPLACEABLE>', sub {
653 if($_[0]->in('TOKEN')) {
654 # When tokenizing, follow more 'intuitive' convention
658 sgml('</REPLACEABLE>', sub {
659 if($_[0]->in('TOKEN')) {
665 sgml('<CITETITLE>', \&italic_on); sgml('</CITETITLE>', \&font_off);
666 sgml('<FOREIGNPHRASE>', \&italic_on); sgml('</FOREIGNPHRASE>', \&font_off);
668 sgml('<LINEANNOTATION>', \&italic_on); sgml('</LINEANNOTATION>', \&font_off);
675 ########################################################################
677 # Other 'inline' elements
679 ########################################################################
681 man_sgml('<EMAIL>', '<');
682 man_sgml('</EMAIL>', '>');
683 man_sgml('<OPTIONAL>', '[');
684 man_sgml('</OPTIONAL>', ']');
686 man_sgml('</TRADEMARK>', "\\u\\s-2TM\\s+2\\d");
688 man_sgml('<COMMENT>', "[Comment: ");
689 man_sgml('</COMMENT>', "]");
691 man_sgml('<QUOTE>', "``");
692 man_sgml('</QUOTE>', "''");
694 #man_sgml('<LITERAL>', '"');
695 #man_sgml('</LITERAL>', '"');
697 # No special presentation:
723 # There doesn't seem to be a good way to represent LITERAL in -man
727 ########################################################################
729 # Paragraph and paragraph-like elements
731 ########################################################################
734 output "\n" unless $newline_last++;
736 # In lists, etc., don't start paragraph with .PP since
737 # the indentation will be gone.
739 if($_[0]->parent->ext->{'nobreak'}==1) {
740 # Usually this is the FIRST element of
741 # a hanging tag, so we MUST not do a full
743 $_[0]->parent->ext->{'nobreak'} = 2;
744 } elsif($_[0]->parent->ext->{'nobreak'}==2) {
745 # Usually these are the NEXT elements of
746 # a hanging tag. If we break using a blank
750 # Normal case. (For indented blocks too, at least
751 # -man isn't so braindead in this area.)
755 # Actually applies to a few other block elements as well
757 output "\n" unless $newline_last++;
760 sgml('<PARA>', \¶_start);
761 sgml('</PARA>', \¶_end);
762 sgml('<SIMPARA>', \¶_start);
763 sgml('</SIMPARA>', \¶_end);
765 # Nothing special, except maybe FIXME set nobreak.
766 sgml('<INFORMALEXAMPLE>', \¶_start);
767 sgml('</INFORMALEXAMPLE>', \¶_end);
773 ########################################################################
775 # Blocks using SS sections
777 ########################################################################
779 # FIXME: We need to consider the effects of SS
780 # in a hanging tag :(
782 # Complete with the optional-title dilemma (again).
783 sgml('<ABSTRACT>', sub {
784 $_[0]->ext->{'title'} = 'ABSTRACT';
785 output "\n" unless $newline_last++;
786 push_output('string');
788 sgml('</ABSTRACT>', sub {
789 my $content = pop_output();
791 # As ABSTRACT is never on the same level as RefSect1,
792 # this leaves us with only .SS in terms of -man macros.
793 output ".SS \"", uc($_[0]->ext->{'title'}), "\"\n";
796 output "\n" unless $newline_last++;
799 # Ah, I needed a break. Example always has a title.
800 man_sgml('<EXAMPLE>', "\n.SS ");
801 sgml('</EXAMPLE>', \¶_end);
804 man_sgml('<SIDEBAR>', "\n.SS ");
805 sgml('</SIDEBAR>', \¶_end);
808 man_sgml('<HIGHLIGHTS>', "\n.SS HIGHLIGHTS\n");
809 sgml('</HIGHLIGHTS>', \¶_end);
814 ########################################################################
816 # Indented 'Block' elements
818 ########################################################################
820 sub indent_block_start
822 output "\n" unless $newline_last++;
827 output "\n" unless $newline_last++;
831 # This element is almost like an admonition (below),
832 # only the default title is blank :)
834 sgml('<BLOCKQUOTE>', sub {
835 $_[0]->ext->{'title'} = '';
836 output "\n" unless $newline_last++;
837 push_output('string');
839 sgml('</BLOCKQUOTE>', sub {
840 my $content = pop_output();
842 indent_block_start();
844 if($_[0]->ext->{'title'}) {
845 output ".B \"", $_[0]->ext->{'title'}, ":\"\n";
850 if($_[0]->ext->{'attribution'}) {
851 output "\n" unless $newline_last++;
852 # One place where roff's space-sensitivity makes sense :)
854 output $_[0]->ext->{'attribution'} . "\n";
860 # Set off admonitions from the rest of the text by indenting.
861 # FIXME: Need to check if this works inside paragraphs, not enclosing them.
863 my $content = pop_output();
865 indent_block_start();
867 # When the admonition is only one paragraph,
868 # it looks nicer if the title was inline.
870 while ($content =~ /^\.PP/gm) { $num_para++ }
872 $content =~ s/^\.PP\n//;
875 output ".B \"" . $_[0]->ext->{'title'} . ":\"\n";
882 # We can't see right now whether or not there is a TITLE
883 # element, so we have to save the output now and add it back
884 # at the end of this admonition.
885 $_[0]->ext->{'title'} = 'Note';
887 # Although admonition_end's indent_block_start will do this,
888 # we need to synchronize the output _now_
889 output "\n" unless $newline_last++;
891 push_output('string');
893 sgml('</NOTE>', \&admonition_end);
896 sgml('<WARNING>', sub {
897 $_[0]->ext->{'title'} = 'Warning';
898 output "\n" unless $newline_last++;
899 push_output('string');
901 sgml('</WARNING>', \&admonition_end);
904 $_[0]->ext->{'title'} = 'Tip';
905 output "\n" unless $newline_last++;
906 push_output('string');
908 sgml('</TIP>', \&admonition_end);
909 sgml('<CAUTION>', sub {
910 $_[0]->ext->{'title'} = 'Caution';
911 output "\n" unless $newline_last++;
912 push_output('string');
914 sgml('</CAUTION>', \&admonition_end);
916 sgml('<IMPORTANT>', sub {
917 $_[0]->ext->{'title'} = 'Important';
918 output "\n" unless $newline_last++;
919 push_output('string');
921 sgml('</IMPORTANT>', \&admonition_end);
934 ########################################################################
938 ########################################################################
941 output "\n" unless $newline_last++;
943 if($_[0]->parent->ext->{'nobreak'}==1) {
944 # Usually this is the FIRST element of
945 # a hanging tag, so we MUST not do a full
947 $_[0]->parent->ext->{'nobreak'} = 2;
952 output(".nf\n") unless $nocollapse_whitespace++;
956 output "\n" unless $newline_last++;
957 output(".fi\n") unless --$nocollapse_whitespace;
960 sgml('<PROGRAMLISTING>', \&verbatim_start);
961 sgml('</PROGRAMLISTING>', \&verbatim_end);
963 sgml('<SCREEN>', \&verbatim_start);
964 sgml('</SCREEN>', \&verbatim_end);
966 sgml('<LITERALLAYOUT>', \&verbatim_start);
967 sgml('</LITERALLAYOUT>', \&verbatim_end);
969 #sgml('<SYNOPSIS>', sub {
970 # if($_[0]->attribute('FORMAT')->value =~ /linespecific/i) {
977 #sgml('</SYNOPSIS>', sub {
978 # if($_[0]->attribute('FORMAT')->value =~ /linespecific/i) {
982 # roffcmd("");# not sure about this.
985 sgml('<SYNOPSIS>', \&verbatim_start);
986 sgml('</SYNOPSIS>', \&verbatim_end);
996 ########################################################################
1000 ########################################################################
1002 # Indent nested lists.
1003 sub indent_list_start {
1004 if($list_nestlevel++) {
1005 output "\n" unless $newline_last++;
1009 sub indent_list_end {
1010 if(--$list_nestlevel) {
1011 output "\n" unless $newline_last++;
1016 sgml('<VARIABLELIST>', \&indent_list_start);
1017 sgml('</VARIABLELIST>', \&indent_list_end);
1018 sgml('<ITEMIZEDLIST>', \&indent_list_start);
1019 sgml('</ITEMIZEDLIST>', \&indent_list_end);
1020 sgml('<ORDEREDLIST>', sub {
1021 indent_list_start();
1022 $_[0]->ext->{'count'} = 1;
1024 sgml('</ORDEREDLIST>', \&indent_list_end);
1025 sgml('<GLOSSLIST>', \&indent_list_start);
1026 sgml('</GLOSSLIST>', \&indent_list_end);
1028 # Output content on one line, bolded.
1029 sgml('<TERM>', sub {
1030 output "\n" unless $newline_last++;
1033 push_output('string');
1035 sgml('</TERM>', sub {
1036 my $term = pop_output();
1043 sgml('<GLOSSTERM>', sub {
1044 output "\n" unless $newline_last++;
1047 push_output('string');
1049 sgml('</GLOSSTERM>', sub {
1050 my $term = pop_output();
1058 sgml('<LISTITEM>', sub {
1060 if($_[0]->in('ITEMIZEDLIST')) {
1061 output "\n" unless $newline_last++;
1062 output ".TP 0.2i\n\\(bu\n";
1066 # Assume Arabic numeration for now.
1067 elsif($_[0]->in('ORDEREDLIST')) {
1068 output "\n" unless $newline_last++;
1069 output ".TP 3\n", $_[0]->parent->ext->{'count'}++, ". \n";
1072 $_[0]->ext->{'nobreak'} = 1;
1074 sgml('<GLOSSDEF>', sub {
1075 $_[0]->ext->{'nobreak'} = 1;
1078 sgml('<SIMPLELIST>', sub {
1079 $_[0]->ext->{'first_member'} = 1;
1082 sgml('<MEMBER>', sub {
1083 my $parent = $_[0]->parent;
1085 if($parent->attribute('TYPE')->value =~ /Inline/i) {
1086 if($parent->ext->{'first_member'}) {
1087 # If this is the first member don't put any commas
1088 $parent->ext->{'first_member'} = 0;
1092 } elsif($parent->attribute('TYPE')->value =~ /Vert/i) {
1093 output "\n" unless $newline_last++;
1102 ########################################################################
1104 # Stuff we don't know how to handle (yet)
1106 ########################################################################
1130 ########################################################################
1132 # Linkage, cross references
1134 ########################################################################
1137 sgml('</ULINK>', sub {
1138 output ' <URL:', $_[0]->attribute('URL')->value, '>';
1142 # If cross reference target is a RefEntry,
1143 # output CiteRefEntry-style references.
1144 sgml('<XREF>', sub {
1145 my $id = $_[0]->attribute('LINKEND')->value;
1146 my $manref = $Refs->get("refentry:$id");
1149 my ($title, $sect) = ($manref =~ /(.*)(\(.*\))/);
1155 $blank_xrefs++ if $write_manpages;
1156 output "[XRef to $id]";
1167 ########################################################################
1171 ########################################################################
1173 man_sgml('|[lt ]|', '<');
1174 man_sgml('|[gt ]|', '>');
1175 man_sgml('|[amp ]|', '&');
1176 man_sgml('|[minus ]|', '-');
1177 man_sgml('|[copy ]|', '(C)');
1178 man_sgml('|[nbsp ]|', '\~');
1179 man_sgml('|[thinsp]|', '\~');
1182 # Default handlers (uncomment these if needed). Right now, these are set
1183 # up to gag on any unrecognised elements, sdata, processing-instructions,
1186 # sgml('start_element',sub { die "Unknown element: " . $_[0]->name; });
1187 # sgml('end_element','');
1189 # This is for weeding out and escaping certain characters.
1190 # This looks like it's inefficient since it's done on every line, but
1191 # in reality, SGMLSpm and sgmlspl parsing ESIS takes _much_ longer.
1195 if(!$write_manpages) { return; }
1196 elsif($raw_cdata) { output $_[0]; return; }
1198 # Escape backslashes
1199 $_[0] =~ s/\\/\\\\/g;
1201 # Escape dots and single quotes in column 1
1202 $_[0] =~ s/^\./\\\&\./;
1203 $_[0] =~ s/^\'/\\\&\'/;
1205 # In non-'pre'-type elements:
1206 if(!$nocollapse_whitespace) {
1207 # Change tabs to spaces
1210 # Do not allow indents at beginning of line
1211 # groff chokes on that.
1215 # If the line is all blank, don't do anything.
1216 if($_[0] eq '') { return; }
1226 # When in whitespace-collapsing mode, we disallow consecutive newlines.
1230 if($nocollapse_whitespace || !$newline_last) {
1239 die "Unknown SDATA: " . $_[0];
1241 sgml('pi',sub { die "Unknown processing instruction: " . $_[0]; });
1242 sgml('entity',sub { die "Unknown external entity: " . $_[0]->name; });
1243 sgml('start_subdoc',sub { die "Unknown subdoc entity: " . $_[0]->name; });
1244 sgml('end_subdoc','');
1245 sgml('conforming','');