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.1.2.1 2002/08/11 20:01:30 hal9 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 sgml('</REFENTRY>', sub {
258 sgml('</REFMETA>', sub {
259 push_output('file', "$manpage_title.$manpage_sect");
261 output <<_END_BANNER;
262 .\\" This manpage has been automatically generated by docbook2man
263 .\\" from a DocBook document. This tool can be found at:
264 .\\" <http://shell.ipoline.com/~elmert/comp/docbook2X/>
265 .\\" Please send any bug reports, improvements, comments, patches,
266 .\\" etc. to Steve Cheng <steve\@ggi-project.org>.
269 my $manpage_date = `date "+%d %B %Y"`;
273 # If the title is not mixed-case, convention says to
274 # uppercase the whole title. (The canonical title is
276 if($manpage_title =~ /[A-Z]/) {
277 output fold_string($manpage_title);
279 output uc(fold_string($manpage_title));
282 output '" "', fold_string($manpage_sect),
283 '" "', fold_string(`date "+%d %B %Y"`),
284 '" "', $manpage_misc,
285 '" "', $manpage_manual,
290 # References to this RefEntry.
291 my $id = $_[0]->parent->attribute('ID')->value;
293 # The 'package name' part of the section should
294 # not be used when citing it.
295 my ($sectnum) = ($manpage_sect =~ /([0-9]*)/);
297 if($_[0]->parent->attribute('XREFLABEL')->value eq '') {
298 $Refs->put("refentry:$id", "$manpage_title($sectnum)");
300 $Refs->put("refentry:$id",
301 $_[0]->parent->attribute('XREFLABEL')->value .
307 sgml('<REFENTRYTITLE>', sub {
308 if($_[0]->in('REFMETA')) {
311 # Manpage citations are in bold.
315 sgml('</REFENTRYTITLE>', sub {
316 if($_[0]->in('REFMETA')) {
318 $manpage_title = pop_output();
323 sgml('<MANVOLNUM>', sub {
324 if($_[0]->in('REFMETA')) {
327 # Manpage citations use ().
331 sgml('</MANVOLNUM>', sub {
332 if($_[0]->in('REFMETA')) {
334 $manpage_sect = pop_output();
339 sgml('<REFMISCINFO>', \&save_cdata);
340 sgml('</REFMISCINFO>', sub {
342 $manpage_misc = fold_string(pop_output());
347 man_sgml('<REFNAMEDIV>', "\n.SH NAME\n");
349 sgml('<REFNAME>', \&save_cdata);
350 sgml('</REFNAME>', sub {
352 push(@manpage_names, pop_output());
355 sgml('<REFPURPOSE>', \&save_cdata);
356 sgml('</REFPURPOSE>', sub {
358 my $manpage_purpose = fold_string(pop_output());
360 for(my $i = 0; $i < $#manpage_names; $i++) {
361 output fold_string($manpage_names[$i]), ', ';
364 output fold_string($manpage_names[$#manpage_names]);
365 output " \\- $manpage_purpose\n";
369 foreach(@manpage_names) {
370 # Don't link to itself
371 if($_ ne $manpage_title) {
372 print LINKSFILE "$manpage_title.$manpage_sect $_.$manpage_sect\n";
377 man_sgml('<REFCLASS>', "\n.sp\n");
385 ########################################################################
387 # SYNOPSIS section and synopses
389 ########################################################################
391 man_sgml('<REFSYNOPSISDIV>', "\n.SH SYNOPSIS\n");
392 man_sgml('</REFSYNOPSISDIV>', "\n");
394 ## FIXME! Must be made into block elements!!
395 #sgml('<FUNCSYNOPSIS>', \&bold_on);
396 #sgml('</FUNCSYNOPSIS>', \&font_off);
397 #sgml('<CMDSYNOPSIS>', \&bold_on);
398 #sgml('</CMDSYNOPSIS>', \&font_off);
400 man_sgml('<FUNCSYNOPSIS>', sub {
401 man_output("\n.sp\n");
404 man_sgml('</FUNCSYNOPSIS>', sub {
409 man_sgml('<CMDSYNOPSIS>', "\n\n");
410 man_sgml('</CMDSYNOPSIS>', "\n\n");
412 man_sgml('<FUNCPROTOTYPE>', "\n.sp\n");
414 # Arguments to functions. This is C convention.
417 if($_[0]->parent->ext->{'inparams'}) {
421 $_[0]->parent->ext->{'inparams'} = 1;
424 man_sgml('<PARAMDEF>', \¶mdef);
425 man_sgml('</FUNCPROTOTYPE>', ");\n");
426 man_sgml('<VOID>', "(void");
427 man_sgml('<VARARGS>', "(...");
433 if(not $_[0]->parent->in('TERM')) {
434 if($_[0]->attribute('CHOICE')->value =~ /opt/i) {
436 } elsif($_[0]->attribute('CHOICE')->value =~ /req/i) {
440 $_[0]->ext->{'count'} = 1;
444 if($_[0]->attribute('REP')->value =~ /^Repeat/i) {
449 if(not $_[0]->parent->in('TERM')) {
450 if($_[0]->attribute('CHOICE')->value =~ /opt/i) {
452 } elsif($_[0]->attribute('CHOICE')->value =~ /req/i) {
460 # my $choice = $_[0]->attribute('CHOICE')->value;
462 # The content model for CmdSynopsis doesn't include #PCDATA,
463 # so we won't see any of the whitespace in the source file,
464 # so we have to add it after each component.
467 if($_[0]->in('GROUP')) {
468 output '| ' if $_[0]->parent->ext->{'count'} > 1;
469 $_[0]->parent->ext->{'count'}++;
470 } elsif($_[0]->attribute('CHOICE')->value =~ /opt/i) {
478 if($_[0]->attribute('REP')->value =~ /^Repeat/i) {
483 if($_[0]->attribute('CHOICE')->value =~ /opt/i and
484 not $_[0]->in('GROUP')) {
489 sgml('<ARG>', \&arg_start);
490 sgml('</ARG>', \&arg_end);
491 sgml('<GROUP>', \&group_start);
492 sgml('</GROUP>', \&group_end);
494 sgml('<OPTION>', \&bold_on);
495 sgml('</OPTION>', \&font_off);
497 man_sgml('<SBR>', "\n ");
500 ########################################################################
504 ########################################################################
506 # The name of the section is handled by TITLE. This just sets
507 # up the roff markup.
508 man_sgml('<REFSECT1>', "\n.SH ");
509 man_sgml('<REFSECT2>', "\n.SS ");
510 man_sgml('<REFSECT3>', "\n.SS ");
513 ########################################################################
517 ########################################################################
519 sgml('<TITLE>', sub {
520 if($_[0]->in('REFERENCE') or $_[0]->in('BOOK')) {
525 sgml('</TITLE>', sub {
526 my $title = fold_string(pop_output());
529 if($_[0]->in('REFERENCE') or $_[0]->in('BOOK')) {
530 # We use TITLE of enclosing Reference or Book as manual name
531 $manpage_manual = $title;
534 elsif(exists $_[0]->parent->ext->{'title'}) {
535 # By far the easiest case. Just fold the string as
536 # above, and then set the parent element's variable.
537 $_[0]->parent->ext->{'title'} = $title;
540 # If the parent element's handlers are lazy,
541 # output the folded string for them :)
542 # We assume they want uppercase and a newline.
543 output '"', uc($title), "\"\n";
548 sgml('<ATTRIBUTION>', sub { push_output('string') });
549 sgml('</ATTRIBUTION>', sub { $_[0]->parent->ext->{'attribution'} = pop_output(); });
553 sgml('<DOCINFO>', sub { push_output('nul'); });
554 sgml('</DOCINFO>', sub { pop_output(); });
555 sgml('<REFSECT1INFO>', sub { push_output('nul'); });
556 sgml('</REFSECT1INFO>', sub { pop_output(); });
557 sgml('<REFSECT2INFO>', sub { push_output('nul'); });
558 sgml('</REFSECT2INFO>', sub { pop_output(); });
559 sgml('<REFSECT3INFO>', sub { push_output('nul'); });
560 sgml('</REFSECT3INFO>', sub { pop_output(); });
562 sgml('<INDEXTERM>', sub { push_output('nul'); });
563 sgml('</INDEXTERM>', sub { pop_output(); });
566 ########################################################################
568 # Set bold on enclosed content
570 ########################################################################
572 sgml('<APPLICATION>', \&bold_on); sgml('</APPLICATION>', \&font_off);
574 sgml('<CLASSNAME>', \&bold_on); sgml('</CLASSNAME>', \&font_off);
575 sgml('<STRUCTNANE>', \&bold_on); sgml('</STRUCTNAME>', \&font_off);
576 sgml('<STRUCTFIELD>', \&bold_on); sgml('</STRUCTFIELD>', \&font_off);
577 sgml('<SYMBOL>', \&bold_on); sgml('</SYMBOL>', \&font_off);
578 sgml('<TYPE>', \&bold_on); sgml('</TYPE>', \&font_off);
580 sgml('<ENVAR>', \&bold_on); sgml('</ENVAR>', \&font_off);
582 sgml('<FUNCTION>', \&bold_on); sgml('</FUNCTION>', \&font_off);
584 sgml('<EMPHASIS>', \&bold_on); sgml('</EMPHASIS>', \&font_off);
586 sgml('<ERRORNAME>', \&bold_on); sgml('</ERRORNAME>', \&font_off);
589 sgml('<COMMAND>', \&bold_on); sgml('</COMMAND>', \&font_off);
591 sgml('<GUIBUTTON>', \&bold_on); sgml('</GUIBUTTON>', \&font_off);
592 sgml('<GUIICON>', \&bold_on); sgml('</GUIICON>', \&font_off);
600 sgml('<ACCEL>', \&bold_on); sgml('</ACCEL>', \&font_off);
601 sgml('<KEYCAP>', \&bold_on); sgml('</KEYCAP>', \&font_off);
602 sgml('<KEYSYM>', \&bold_on); sgml('</KEYSYM>', \&font_off);
607 sgml('<USERINPUT>', \&bold_on); sgml('</USERINPUT>', \&font_off);
609 sgml('<INTERFACEDEFINITION>', \&bold_on);
610 sgml('</INTERFACEDEFINITION>', \&font_off);
612 # May need to look at the CLASS
613 sgml('<SYSTEMITEM>', \&bold_on);
614 sgml('</SYSTEMITEM>', \&font_off);
620 ########################################################################
622 # Set italic on enclosed content
624 ########################################################################
626 sgml('<FIRSTTERM>', \&italic_on); sgml('</FIRSTTERM>', \&font_off);
628 sgml('<FILENAME>', \&italic_on); sgml('</FILENAME>', \&font_off);
629 sgml('<PARAMETER>', \&italic_on); sgml('</PARAMETER>', \&font_off);
630 sgml('<PROPERTY>', \&italic_on); sgml('</PROPERTY>', \&font_off);
632 sgml('<REPLACEABLE>', sub {
634 if($_[0]->in('TOKEN')) {
635 # When tokenizing, follow more 'intuitive' convention
639 sgml('</REPLACEABLE>', sub {
640 if($_[0]->in('TOKEN')) {
646 sgml('<CITETITLE>', \&italic_on); sgml('</CITETITLE>', \&font_off);
647 sgml('<FOREIGNPHRASE>', \&italic_on); sgml('</FOREIGNPHRASE>', \&font_off);
649 sgml('<LINEANNOTATION>', \&italic_on); sgml('</LINEANNOTATION>', \&font_off);
656 ########################################################################
658 # Other 'inline' elements
660 ########################################################################
662 man_sgml('<EMAIL>', '<');
663 man_sgml('</EMAIL>', '>');
664 man_sgml('<OPTIONAL>', '[');
665 man_sgml('</OPTIONAL>', ']');
667 man_sgml('</TRADEMARK>', "\\u\\s-2TM\\s+2\\d");
669 man_sgml('<COMMENT>', "[Comment: ");
670 man_sgml('</COMMENT>', "]");
672 man_sgml('<QUOTE>', "``");
673 man_sgml('</QUOTE>', "''");
675 #man_sgml('<LITERAL>', '"');
676 #man_sgml('</LITERAL>', '"');
678 # No special presentation:
704 # There doesn't seem to be a good way to represent LITERAL in -man
708 ########################################################################
710 # Paragraph and paragraph-like elements
712 ########################################################################
715 output "\n" unless $newline_last++;
717 # In lists, etc., don't start paragraph with .PP since
718 # the indentation will be gone.
720 if($_[0]->parent->ext->{'nobreak'}==1) {
721 # Usually this is the FIRST element of
722 # a hanging tag, so we MUST not do a full
724 $_[0]->parent->ext->{'nobreak'} = 2;
725 } elsif($_[0]->parent->ext->{'nobreak'}==2) {
726 # Usually these are the NEXT elements of
727 # a hanging tag. If we break using a blank
731 # Normal case. (For indented blocks too, at least
732 # -man isn't so braindead in this area.)
736 # Actually applies to a few other block elements as well
738 output "\n" unless $newline_last++;
741 sgml('<PARA>', \¶_start);
742 sgml('</PARA>', \¶_end);
743 sgml('<SIMPARA>', \¶_start);
744 sgml('</SIMPARA>', \¶_end);
746 # Nothing special, except maybe FIXME set nobreak.
747 sgml('<INFORMALEXAMPLE>', \¶_start);
748 sgml('</INFORMALEXAMPLE>', \¶_end);
754 ########################################################################
756 # Blocks using SS sections
758 ########################################################################
760 # FIXME: We need to consider the effects of SS
761 # in a hanging tag :(
763 # Complete with the optional-title dilemma (again).
764 sgml('<ABSTRACT>', sub {
765 $_[0]->ext->{'title'} = 'ABSTRACT';
766 output "\n" unless $newline_last++;
767 push_output('string');
769 sgml('</ABSTRACT>', sub {
770 my $content = pop_output();
772 # As ABSTRACT is never on the same level as RefSect1,
773 # this leaves us with only .SS in terms of -man macros.
774 output ".SS \"", uc($_[0]->ext->{'title'}), "\"\n";
777 output "\n" unless $newline_last++;
780 # Ah, I needed a break. Example always has a title.
781 man_sgml('<EXAMPLE>', "\n.SS ");
782 sgml('</EXAMPLE>', \¶_end);
785 man_sgml('<SIDEBAR>', "\n.SS ");
786 sgml('</SIDEBAR>', \¶_end);
789 man_sgml('<HIGHLIGHTS>', "\n.SS HIGHLIGHTS\n");
790 sgml('</HIGHLIGHTS>', \¶_end);
795 ########################################################################
797 # Indented 'Block' elements
799 ########################################################################
801 sub indent_block_start
803 output "\n" unless $newline_last++;
808 output "\n" unless $newline_last++;
812 # This element is almost like an admonition (below),
813 # only the default title is blank :)
815 sgml('<BLOCKQUOTE>', sub {
816 $_[0]->ext->{'title'} = '';
817 output "\n" unless $newline_last++;
818 push_output('string');
820 sgml('</BLOCKQUOTE>', sub {
821 my $content = pop_output();
823 indent_block_start();
825 if($_[0]->ext->{'title'}) {
826 output ".B \"", $_[0]->ext->{'title'}, ":\"\n";
831 if($_[0]->ext->{'attribution'}) {
832 output "\n" unless $newline_last++;
833 # One place where roff's space-sensitivity makes sense :)
835 output $_[0]->ext->{'attribution'} . "\n";
841 # Set off admonitions from the rest of the text by indenting.
842 # FIXME: Need to check if this works inside paragraphs, not enclosing them.
844 my $content = pop_output();
846 indent_block_start();
848 # When the admonition is only one paragraph,
849 # it looks nicer if the title was inline.
851 while ($content =~ /^\.PP/gm) { $num_para++ }
853 $content =~ s/^\.PP\n//;
856 output ".B \"" . $_[0]->ext->{'title'} . ":\"\n";
863 # We can't see right now whether or not there is a TITLE
864 # element, so we have to save the output now and add it back
865 # at the end of this admonition.
866 $_[0]->ext->{'title'} = 'Note';
868 # Although admonition_end's indent_block_start will do this,
869 # we need to synchronize the output _now_
870 output "\n" unless $newline_last++;
872 push_output('string');
874 sgml('</NOTE>', \&admonition_end);
877 sgml('<WARNING>', sub {
878 $_[0]->ext->{'title'} = 'Warning';
879 output "\n" unless $newline_last++;
880 push_output('string');
882 sgml('</WARNING>', \&admonition_end);
885 $_[0]->ext->{'title'} = 'Tip';
886 output "\n" unless $newline_last++;
887 push_output('string');
889 sgml('</TIP>', \&admonition_end);
890 sgml('<CAUTION>', sub {
891 $_[0]->ext->{'title'} = 'Caution';
892 output "\n" unless $newline_last++;
893 push_output('string');
895 sgml('</CAUTION>', \&admonition_end);
897 sgml('<IMPORTANT>', sub {
898 $_[0]->ext->{'title'} = 'Important';
899 output "\n" unless $newline_last++;
900 push_output('string');
902 sgml('</IMPORTANT>', \&admonition_end);
915 ########################################################################
919 ########################################################################
922 output "\n" unless $newline_last++;
924 if($_[0]->parent->ext->{'nobreak'}==1) {
925 # Usually this is the FIRST element of
926 # a hanging tag, so we MUST not do a full
928 $_[0]->parent->ext->{'nobreak'} = 2;
933 output(".nf\n") unless $nocollapse_whitespace++;
937 output "\n" unless $newline_last++;
938 output(".fi\n") unless --$nocollapse_whitespace;
941 sgml('<PROGRAMLISTING>', \&verbatim_start);
942 sgml('</PROGRAMLISTING>', \&verbatim_end);
944 sgml('<SCREEN>', \&verbatim_start);
945 sgml('</SCREEN>', \&verbatim_end);
947 sgml('<LITERALLAYOUT>', \&verbatim_start);
948 sgml('</LITERALLAYOUT>', \&verbatim_end);
950 #sgml('<SYNOPSIS>', sub {
951 # if($_[0]->attribute('FORMAT')->value =~ /linespecific/i) {
958 #sgml('</SYNOPSIS>', sub {
959 # if($_[0]->attribute('FORMAT')->value =~ /linespecific/i) {
963 # roffcmd("");# not sure about this.
966 sgml('<SYNOPSIS>', \&verbatim_start);
967 sgml('</SYNOPSIS>', \&verbatim_end);
977 ########################################################################
981 ########################################################################
983 # Indent nested lists.
984 sub indent_list_start {
985 if($list_nestlevel++) {
986 output "\n" unless $newline_last++;
990 sub indent_list_end {
991 if(--$list_nestlevel) {
992 output "\n" unless $newline_last++;
997 sgml('<VARIABLELIST>', \&indent_list_start);
998 sgml('</VARIABLELIST>', \&indent_list_end);
999 sgml('<ITEMIZEDLIST>', \&indent_list_start);
1000 sgml('</ITEMIZEDLIST>', \&indent_list_end);
1001 sgml('<ORDEREDLIST>', sub {
1002 indent_list_start();
1003 $_[0]->ext->{'count'} = 1;
1005 sgml('</ORDEREDLIST>', \&indent_list_end);
1006 sgml('<GLOSSLIST>', \&indent_list_start);
1007 sgml('</GLOSSLIST>', \&indent_list_end);
1009 # Output content on one line, bolded.
1010 sgml('<TERM>', sub {
1011 output "\n" unless $newline_last++;
1014 push_output('string');
1016 sgml('</TERM>', sub {
1017 my $term = pop_output();
1024 sgml('<GLOSSTERM>', sub {
1025 output "\n" unless $newline_last++;
1028 push_output('string');
1030 sgml('</GLOSSTERM>', sub {
1031 my $term = pop_output();
1039 sgml('<LISTITEM>', sub {
1041 if($_[0]->in('ITEMIZEDLIST')) {
1042 output "\n" unless $newline_last++;
1043 output ".TP 0.2i\n\\(bu\n";
1047 # Assume Arabic numeration for now.
1048 elsif($_[0]->in('ORDEREDLIST')) {
1049 output "\n" unless $newline_last++;
1050 output ".TP 3\n", $_[0]->parent->ext->{'count'}++, ". \n";
1053 $_[0]->ext->{'nobreak'} = 1;
1055 sgml('<GLOSSDEF>', sub {
1056 $_[0]->ext->{'nobreak'} = 1;
1059 sgml('<SIMPLELIST>', sub {
1060 $_[0]->ext->{'first_member'} = 1;
1063 sgml('<MEMBER>', sub {
1064 my $parent = $_[0]->parent;
1066 if($parent->attribute('TYPE')->value =~ /Inline/i) {
1067 if($parent->ext->{'first_member'}) {
1068 # If this is the first member don't put any commas
1069 $parent->ext->{'first_member'} = 0;
1073 } elsif($parent->attribute('TYPE')->value =~ /Vert/i) {
1074 output "\n" unless $newline_last++;
1083 ########################################################################
1085 # Stuff we don't know how to handle (yet)
1087 ########################################################################
1111 ########################################################################
1113 # Linkage, cross references
1115 ########################################################################
1118 sgml('</ULINK>', sub {
1119 output ' <URL:', $_[0]->attribute('URL')->value, '>';
1123 # If cross reference target is a RefEntry,
1124 # output CiteRefEntry-style references.
1125 sgml('<XREF>', sub {
1126 my $id = $_[0]->attribute('LINKEND')->value;
1127 my $manref = $Refs->get("refentry:$id");
1130 my ($title, $sect) = ($manref =~ /(.*)(\(.*\))/);
1136 $blank_xrefs++ if $write_manpages;
1137 output "[XRef to $id]";
1148 ########################################################################
1152 ########################################################################
1154 man_sgml('|[lt ]|', '<');
1155 man_sgml('|[gt ]|', '>');
1156 man_sgml('|[amp ]|', '&');
1159 # Default handlers (uncomment these if needed). Right now, these are set
1160 # up to gag on any unrecognised elements, sdata, processing-instructions,
1163 # sgml('start_element',sub { die "Unknown element: " . $_[0]->name; });
1164 # sgml('end_element','');
1166 # This is for weeding out and escaping certain characters.
1167 # This looks like it's inefficient since it's done on every line, but
1168 # in reality, SGMLSpm and sgmlspl parsing ESIS takes _much_ longer.
1172 if(!$write_manpages) { return; }
1173 elsif($raw_cdata) { output $_[0]; return; }
1175 # Escape backslashes
1176 $_[0] =~ s/\\/\\\\/g;
1178 # In non-'pre'-type elements:
1179 if(!$nocollapse_whitespace) {
1180 # Change tabs to spaces
1183 # Do not allow indents at beginning of line
1184 # groff chokes on that.
1188 # If the line is all blank, don't do anything.
1189 if($_[0] eq '') { return; }
1191 $_[0] =~ s/^\./\\\&\./;
1193 # Argh... roff doesn't like ' either...
1194 $_[0] =~ s/^\'/\\\&\'/;
1204 # When in whitespace-collapsing mode, we disallow consecutive newlines.
1208 if($nocollapse_whitespace || !$newline_last) {
1217 if($_[0] =~ /\[minus \]/) { output "-"; }
1218 elsif($_[0] =~ /\[copy \]/) { output "(C)"; }
1219 else { die "Unknown SDATA: " . $_[0]; }
1221 sgml('pi',sub { die "Unknown processing instruction: " . $_[0]; });
1222 sgml('entity',sub { die "Unknown external entity: " . $_[0]->name; });
1223 sgml('start_subdoc',sub { die "Unknown subdoc entity: " . $_[0]->name; });
1224 sgml('end_subdoc','');
1225 sgml('conforming','');