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 use SGMLS; # Use the SGMLS package.
56 use SGMLS::Output; # Use stack-based output.
59 ########################################################################
60 # SGMLSPL script produced automatically by the script sgmlspl.pl
62 # Document Type: any, but processes only RefEntries
64 ########################################################################
71 $raw_cdata = 1; # Makes it a bit faster.
74 open(LINKSFILE, ">manpage.links");
76 $Refs = new SGMLS::Refs("manpage.refs");
81 print STDERR "Warning: output contains unresolved XRefs\n";
88 ########################################################################
92 ########################################################################
94 # Our own version of sgml() and output() to allow simple string output
95 # to play well with roff's stupid whitespace rules.
99 if(ref($_[1]) eq 'CODE') {
108 # \n at the beginning means start at beginning of line
110 $sub = 'sub { output "\n" unless $newline_last++; ';
112 sgml($_[0], eval('sub { output "\n" unless $newline_last++; }'));
113 } elsif($s =~ /\n$/) {
114 sgml($_[0], eval("sub { output \"\\n\" unless \$newline_last++; output '$s'; }"));
116 sgml($_[0], eval("sub { output \"\\n\" unless \$newline_last; output '$s'; \$newline_last = 0; }"));
120 sgml($_[0], eval("sub { output '$s'; \$newline_last = 1; }"));
122 sgml($_[0], eval("sub { output '$s'; \$newline_last = 0; }"));
131 output "\n" unless $newline_last++;
139 $newline_last = (pop(@_) =~ /\n$/);
141 $newline_last = ($_ =~ /\n$/)
145 # Fold lines into one, quote some characters
153 # Change tabs to spaces
156 # Trim whitespace from beginning and end.
166 push_output('string');
171 # If the last font is also bold, don't change anything.
172 # Basically this is to just get more readable man output.
173 if($fontstack[$#fontstack] ne 'bold') {
179 push(@fontstack, 'bold');
184 # If the last font is also italic, don't change anything.
185 if($fontstack[$#fontstack] ne 'italic') {
191 push(@fontstack, 'italic');
196 my $thisfont = pop(@fontstack);
197 my $lastfont = $fontstack[$#fontstack];
199 # Only output font change if it is different
200 if($thisfont ne $lastfont) {
201 if($raw_cdata) { return; }
202 elsif($lastfont eq 'bold') { output '\fB'; }
203 elsif($lastfont eq 'italic') { output '\fI'; }
204 else { output '\fR'; }
215 ########################################################################
219 ########################################################################
221 sgml('<REFENTRY>', sub {
222 # This will be overwritten at end of REFMETA, when we know the name of the page.
225 $write_manpages = 1; # Currently writing manpage.
227 $nocollapse_whitespace = 0; # Current whitespace collapse counter.
228 $newline_last = 1; # At beginning of line?
229 # Just a bit of warning, you will see this variable manipulated
230 # manually a lot. It makes the code harder to follow but it
231 # saves you from having to worry about collapsing at the end of
232 # parse, stopping at verbatims, etc.
233 $raw_cdata = 0; # Instructs certain output functions to
234 # leave CDATA alone, so we can assign
235 # it to a string and process it, etc.
236 @fontstack = (); # Fonts being activated.
238 $manpage_title = ''; # Needed for indexing.
244 $list_nestlevel = 0; # Indent certain nested content.
246 sgml('</REFENTRY>', sub {
256 sgml('</REFMETA>', sub {
257 push_output('file', "$manpage_title.$manpage_sect");
259 output <<_END_BANNER;
260 .\\" This manpage has been generated by docbook2man-spec.pl
261 .\\" (included in the Privoxy source tarball) from a DocBook document.
264 my $manpage_date = `date "+%d %B %Y"`;
268 # If the title is not mixed-case, convention says to
269 # uppercase the whole title. (The canonical title is
271 if($manpage_title =~ /[A-Z]/) {
272 output fold_string($manpage_title);
274 output uc(fold_string($manpage_title));
277 output '" "', fold_string($manpage_sect),
278 '" "', fold_string(`date "+%d %B %Y"`),
279 '" "', $manpage_misc,
280 '" "', $manpage_manual,
285 # References to this RefEntry.
286 my $id = $_[0]->parent->attribute('ID')->value;
288 # The 'package name' part of the section should
289 # not be used when citing it.
290 my ($sectnum) = ($manpage_sect =~ /([0-9]*)/);
292 if($_[0]->parent->attribute('XREFLABEL')->value eq '') {
293 $Refs->put("refentry:$id", "$manpage_title($sectnum)");
295 $Refs->put("refentry:$id",
296 $_[0]->parent->attribute('XREFLABEL')->value .
302 sgml('<REFENTRYTITLE>', sub {
303 if($_[0]->in('REFMETA')) {
306 # Manpage citations are in bold.
310 sgml('</REFENTRYTITLE>', sub {
311 if($_[0]->in('REFMETA')) {
313 $manpage_title = pop_output();
318 sgml('<MANVOLNUM>', sub {
319 if($_[0]->in('REFMETA')) {
322 # Manpage citations use ().
326 sgml('</MANVOLNUM>', sub {
327 if($_[0]->in('REFMETA')) {
329 $manpage_sect = pop_output();
334 sgml('<REFMISCINFO>', \&save_cdata);
335 sgml('</REFMISCINFO>', sub {
337 $manpage_misc = fold_string(pop_output());
342 man_sgml('<REFNAMEDIV>', "\n.SH NAME\n");
344 sgml('<REFNAME>', \&save_cdata);
345 sgml('</REFNAME>', sub {
347 push(@manpage_names, pop_output());
350 sgml('<REFPURPOSE>', \&save_cdata);
351 sgml('</REFPURPOSE>', sub {
353 my $manpage_purpose = fold_string(pop_output());
355 for(my $i = 0; $i < $#manpage_names; $i++) {
356 output fold_string($manpage_names[$i]), ', ';
359 output fold_string($manpage_names[$#manpage_names]);
360 output " \\- $manpage_purpose\n";
364 foreach(@manpage_names) {
365 # Don't link to itself
366 if($_ ne $manpage_title) {
367 print LINKSFILE "$manpage_title.$manpage_sect $_.$manpage_sect\n";
372 man_sgml('<REFCLASS>', "\n.sp\n");
380 ########################################################################
382 # SYNOPSIS section and synopses
384 ########################################################################
386 man_sgml('<REFSYNOPSISDIV>', "\n.SH SYNOPSIS\n");
387 man_sgml('</REFSYNOPSISDIV>', "\n");
389 ## FIXME! Must be made into block elements!!
390 #sgml('<FUNCSYNOPSIS>', \&bold_on);
391 #sgml('</FUNCSYNOPSIS>', \&font_off);
392 #sgml('<CMDSYNOPSIS>', \&bold_on);
393 #sgml('</CMDSYNOPSIS>', \&font_off);
395 man_sgml('<FUNCSYNOPSIS>', sub {
396 man_output("\n.sp\n");
399 man_sgml('</FUNCSYNOPSIS>', sub {
404 man_sgml('<CMDSYNOPSIS>', "\n\n");
405 man_sgml('</CMDSYNOPSIS>', "\n\n");
407 man_sgml('<FUNCPROTOTYPE>', "\n.sp\n");
409 # Arguments to functions. This is C convention.
412 if($_[0]->parent->ext->{'inparams'}) {
416 $_[0]->parent->ext->{'inparams'} = 1;
419 man_sgml('<PARAMDEF>', \¶mdef);
420 man_sgml('</FUNCPROTOTYPE>', ");\n");
421 man_sgml('<VOID>', "(void");
422 man_sgml('<VARARGS>', "(...");
428 if(not $_[0]->parent->in('TERM')) {
429 if($_[0]->attribute('CHOICE')->value =~ /opt/i) {
431 } elsif($_[0]->attribute('CHOICE')->value =~ /req/i) {
435 $_[0]->ext->{'count'} = 1;
439 if($_[0]->attribute('REP')->value =~ /^Repeat/i) {
444 if(not $_[0]->parent->in('TERM')) {
445 if($_[0]->attribute('CHOICE')->value =~ /opt/i) {
447 } elsif($_[0]->attribute('CHOICE')->value =~ /req/i) {
455 # my $choice = $_[0]->attribute('CHOICE')->value;
457 # The content model for CmdSynopsis doesn't include #PCDATA,
458 # so we won't see any of the whitespace in the source file,
459 # so we have to add it after each component.
462 if($_[0]->in('GROUP')) {
463 output '| ' if $_[0]->parent->ext->{'count'} > 1;
464 $_[0]->parent->ext->{'count'}++;
465 } elsif($_[0]->attribute('CHOICE')->value =~ /opt/i) {
473 if($_[0]->attribute('REP')->value =~ /^Repeat/i) {
478 if($_[0]->attribute('CHOICE')->value =~ /opt/i and
479 not $_[0]->in('GROUP')) {
484 sgml('<ARG>', \&arg_start);
485 sgml('</ARG>', \&arg_end);
486 sgml('<GROUP>', \&group_start);
487 sgml('</GROUP>', \&group_end);
489 sgml('<OPTION>', \&bold_on);
490 sgml('</OPTION>', \&font_off);
492 man_sgml('<SBR>', "\n ");
495 ########################################################################
499 ########################################################################
501 # The name of the section is handled by TITLE. This just sets
502 # up the roff markup.
503 man_sgml('<REFSECT1>', "\n.SH ");
504 man_sgml('<REFSECT2>', "\n.SS ");
505 man_sgml('<REFSECT3>', "\n.SS ");
508 ########################################################################
512 ########################################################################
514 sgml('<TITLE>', sub {
515 if($_[0]->in('REFERENCE') or $_[0]->in('BOOK')) {
520 sgml('</TITLE>', sub {
521 my $title = fold_string(pop_output());
524 if($_[0]->in('REFERENCE') or $_[0]->in('BOOK')) {
525 # We use TITLE of enclosing Reference or Book as manual name
526 $manpage_manual = $title;
529 elsif(exists $_[0]->parent->ext->{'title'}) {
530 # By far the easiest case. Just fold the string as
531 # above, and then set the parent element's variable.
532 $_[0]->parent->ext->{'title'} = $title;
535 # If the parent element's handlers are lazy,
536 # output the folded string for them :)
537 # We assume they want uppercase and a newline.
538 output '"', uc($title), "\"\n";
543 sgml('<ATTRIBUTION>', sub { push_output('string') });
544 sgml('</ATTRIBUTION>', sub { $_[0]->parent->ext->{'attribution'} = pop_output(); });
548 sgml('<DOCINFO>', sub { push_output('nul'); });
549 sgml('</DOCINFO>', sub { pop_output(); });
550 sgml('<REFSECT1INFO>', sub { push_output('nul'); });
551 sgml('</REFSECT1INFO>', sub { pop_output(); });
552 sgml('<REFSECT2INFO>', sub { push_output('nul'); });
553 sgml('</REFSECT2INFO>', sub { pop_output(); });
554 sgml('<REFSECT3INFO>', sub { push_output('nul'); });
555 sgml('</REFSECT3INFO>', sub { pop_output(); });
557 sgml('<INDEXTERM>', sub { push_output('nul'); });
558 sgml('</INDEXTERM>', sub { pop_output(); });
561 ########################################################################
563 # Set bold on enclosed content
565 ########################################################################
567 sgml('<APPLICATION>', \&bold_on); sgml('</APPLICATION>', \&font_off);
569 sgml('<CLASSNAME>', \&bold_on); sgml('</CLASSNAME>', \&font_off);
570 sgml('<STRUCTNANE>', \&bold_on); sgml('</STRUCTNAME>', \&font_off);
571 sgml('<STRUCTFIELD>', \&bold_on); sgml('</STRUCTFIELD>', \&font_off);
572 sgml('<SYMBOL>', \&bold_on); sgml('</SYMBOL>', \&font_off);
573 sgml('<TYPE>', \&bold_on); sgml('</TYPE>', \&font_off);
575 sgml('<ENVAR>', \&bold_on); sgml('</ENVAR>', \&font_off);
577 sgml('<FUNCTION>', \&bold_on); sgml('</FUNCTION>', \&font_off);
579 sgml('<EMPHASIS>', \&bold_on); sgml('</EMPHASIS>', \&font_off);
581 sgml('<ERRORNAME>', \&bold_on); sgml('</ERRORNAME>', \&font_off);
584 sgml('<COMMAND>', \&bold_on); sgml('</COMMAND>', \&font_off);
586 sgml('<GUIBUTTON>', \&bold_on); sgml('</GUIBUTTON>', \&font_off);
587 sgml('<GUIICON>', \&bold_on); sgml('</GUIICON>', \&font_off);
595 sgml('<ACCEL>', \&bold_on); sgml('</ACCEL>', \&font_off);
596 sgml('<KEYCAP>', \&bold_on); sgml('</KEYCAP>', \&font_off);
597 sgml('<KEYSYM>', \&bold_on); sgml('</KEYSYM>', \&font_off);
602 sgml('<USERINPUT>', \&bold_on); sgml('</USERINPUT>', \&font_off);
604 sgml('<INTERFACEDEFINITION>', \&bold_on);
605 sgml('</INTERFACEDEFINITION>', \&font_off);
607 # May need to look at the CLASS
608 sgml('<SYSTEMITEM>', \&bold_on);
609 sgml('</SYSTEMITEM>', \&font_off);
615 ########################################################################
617 # Set italic on enclosed content
619 ########################################################################
621 sgml('<FIRSTTERM>', \&italic_on); sgml('</FIRSTTERM>', \&font_off);
623 sgml('<FILENAME>', \&italic_on); sgml('</FILENAME>', \&font_off);
624 sgml('<PARAMETER>', \&italic_on); sgml('</PARAMETER>', \&font_off);
625 sgml('<PROPERTY>', \&italic_on); sgml('</PROPERTY>', \&font_off);
627 sgml('<REPLACEABLE>', sub {
629 if($_[0]->in('TOKEN')) {
630 # When tokenizing, follow more 'intuitive' convention
634 sgml('</REPLACEABLE>', sub {
635 if($_[0]->in('TOKEN')) {
641 sgml('<CITETITLE>', \&italic_on); sgml('</CITETITLE>', \&font_off);
642 sgml('<FOREIGNPHRASE>', \&italic_on); sgml('</FOREIGNPHRASE>', \&font_off);
644 sgml('<LINEANNOTATION>', \&italic_on); sgml('</LINEANNOTATION>', \&font_off);
651 ########################################################################
653 # Other 'inline' elements
655 ########################################################################
657 man_sgml('<EMAIL>', '<');
658 man_sgml('</EMAIL>', '>');
659 man_sgml('<OPTIONAL>', '[');
660 man_sgml('</OPTIONAL>', ']');
662 man_sgml('</TRADEMARK>', "\\u\\s-2TM\\s+2\\d");
664 man_sgml('<COMMENT>', "[Comment: ");
665 man_sgml('</COMMENT>', "]");
667 man_sgml('<QUOTE>', "``");
668 man_sgml('</QUOTE>', "''");
670 #man_sgml('<LITERAL>', '"');
671 #man_sgml('</LITERAL>', '"');
673 # No special presentation:
699 # There doesn't seem to be a good way to represent LITERAL in -man
703 ########################################################################
705 # Paragraph and paragraph-like elements
707 ########################################################################
710 output "\n" unless $newline_last++;
712 # In lists, etc., don't start paragraph with .PP since
713 # the indentation will be gone.
715 if($_[0]->parent->ext->{'nobreak'}==1) {
716 # Usually this is the FIRST element of
717 # a hanging tag, so we MUST not do a full
719 $_[0]->parent->ext->{'nobreak'} = 2;
720 } elsif($_[0]->parent->ext->{'nobreak'}==2) {
721 # Usually these are the NEXT elements of
722 # a hanging tag. If we break using a blank
726 # Normal case. (For indented blocks too, at least
727 # -man isn't so braindead in this area.)
731 # Actually applies to a few other block elements as well
733 output "\n" unless $newline_last++;
736 sgml('<PARA>', \¶_start);
737 sgml('</PARA>', \¶_end);
738 sgml('<SIMPARA>', \¶_start);
739 sgml('</SIMPARA>', \¶_end);
741 # Nothing special, except maybe FIXME set nobreak.
742 sgml('<INFORMALEXAMPLE>', \¶_start);
743 sgml('</INFORMALEXAMPLE>', \¶_end);
749 ########################################################################
751 # Blocks using SS sections
753 ########################################################################
755 # FIXME: We need to consider the effects of SS
756 # in a hanging tag :(
758 # Complete with the optional-title dilemma (again).
759 sgml('<ABSTRACT>', sub {
760 $_[0]->ext->{'title'} = 'ABSTRACT';
761 output "\n" unless $newline_last++;
762 push_output('string');
764 sgml('</ABSTRACT>', sub {
765 my $content = pop_output();
767 # As ABSTRACT is never on the same level as RefSect1,
768 # this leaves us with only .SS in terms of -man macros.
769 output ".SS \"", uc($_[0]->ext->{'title'}), "\"\n";
772 output "\n" unless $newline_last++;
775 # Ah, I needed a break. Example always has a title.
776 man_sgml('<EXAMPLE>', "\n.SS ");
777 sgml('</EXAMPLE>', \¶_end);
780 man_sgml('<SIDEBAR>', "\n.SS ");
781 sgml('</SIDEBAR>', \¶_end);
784 man_sgml('<HIGHLIGHTS>', "\n.SS HIGHLIGHTS\n");
785 sgml('</HIGHLIGHTS>', \¶_end);
790 ########################################################################
792 # Indented 'Block' elements
794 ########################################################################
796 sub indent_block_start
798 output "\n" unless $newline_last++;
803 output "\n" unless $newline_last++;
807 # This element is almost like an admonition (below),
808 # only the default title is blank :)
810 sgml('<BLOCKQUOTE>', sub {
811 $_[0]->ext->{'title'} = '';
812 output "\n" unless $newline_last++;
813 push_output('string');
815 sgml('</BLOCKQUOTE>', sub {
816 my $content = pop_output();
818 indent_block_start();
820 if($_[0]->ext->{'title'}) {
821 output ".B \"", $_[0]->ext->{'title'}, ":\"\n";
826 if($_[0]->ext->{'attribution'}) {
827 output "\n" unless $newline_last++;
828 # One place where roff's space-sensitivity makes sense :)
830 output $_[0]->ext->{'attribution'} . "\n";
836 # Set off admonitions from the rest of the text by indenting.
837 # FIXME: Need to check if this works inside paragraphs, not enclosing them.
839 my $content = pop_output();
841 indent_block_start();
843 # When the admonition is only one paragraph,
844 # it looks nicer if the title was inline.
846 while ($content =~ /^\.PP/gm) { $num_para++ }
848 $content =~ s/^\.PP\n//;
851 output ".B \"" . $_[0]->ext->{'title'} . ":\"\n";
858 # We can't see right now whether or not there is a TITLE
859 # element, so we have to save the output now and add it back
860 # at the end of this admonition.
861 $_[0]->ext->{'title'} = 'Note';
863 # Although admonition_end's indent_block_start will do this,
864 # we need to synchronize the output _now_
865 output "\n" unless $newline_last++;
867 push_output('string');
869 sgml('</NOTE>', \&admonition_end);
872 sgml('<WARNING>', sub {
873 $_[0]->ext->{'title'} = 'Warning';
874 output "\n" unless $newline_last++;
875 push_output('string');
877 sgml('</WARNING>', \&admonition_end);
880 $_[0]->ext->{'title'} = 'Tip';
881 output "\n" unless $newline_last++;
882 push_output('string');
884 sgml('</TIP>', \&admonition_end);
885 sgml('<CAUTION>', sub {
886 $_[0]->ext->{'title'} = 'Caution';
887 output "\n" unless $newline_last++;
888 push_output('string');
890 sgml('</CAUTION>', \&admonition_end);
892 sgml('<IMPORTANT>', sub {
893 $_[0]->ext->{'title'} = 'Important';
894 output "\n" unless $newline_last++;
895 push_output('string');
897 sgml('</IMPORTANT>', \&admonition_end);
910 ########################################################################
914 ########################################################################
917 output "\n" unless $newline_last++;
919 if($_[0]->parent->ext->{'nobreak'}==1) {
920 # Usually this is the FIRST element of
921 # a hanging tag, so we MUST not do a full
923 $_[0]->parent->ext->{'nobreak'} = 2;
928 output(".nf\n") unless $nocollapse_whitespace++;
932 output "\n" unless $newline_last++;
933 output(".fi\n") unless --$nocollapse_whitespace;
936 sgml('<PROGRAMLISTING>', \&verbatim_start);
937 sgml('</PROGRAMLISTING>', \&verbatim_end);
939 sgml('<SCREEN>', \&verbatim_start);
940 sgml('</SCREEN>', \&verbatim_end);
942 sgml('<LITERALLAYOUT>', \&verbatim_start);
943 sgml('</LITERALLAYOUT>', \&verbatim_end);
945 #sgml('<SYNOPSIS>', sub {
946 # if($_[0]->attribute('FORMAT')->value =~ /linespecific/i) {
953 #sgml('</SYNOPSIS>', sub {
954 # if($_[0]->attribute('FORMAT')->value =~ /linespecific/i) {
958 # roffcmd("");# not sure about this.
961 sgml('<SYNOPSIS>', \&verbatim_start);
962 sgml('</SYNOPSIS>', \&verbatim_end);
972 ########################################################################
976 ########################################################################
978 # Indent nested lists.
979 sub indent_list_start {
980 if($list_nestlevel++) {
981 output "\n" unless $newline_last++;
985 sub indent_list_end {
986 if(--$list_nestlevel) {
987 output "\n" unless $newline_last++;
992 sgml('<VARIABLELIST>', \&indent_list_start);
993 sgml('</VARIABLELIST>', \&indent_list_end);
994 sgml('<ITEMIZEDLIST>', \&indent_list_start);
995 sgml('</ITEMIZEDLIST>', \&indent_list_end);
996 sgml('<ORDEREDLIST>', sub {
998 $_[0]->ext->{'count'} = 1;
1000 sgml('</ORDEREDLIST>', \&indent_list_end);
1001 sgml('<GLOSSLIST>', \&indent_list_start);
1002 sgml('</GLOSSLIST>', \&indent_list_end);
1004 # Output content on one line, bolded.
1005 sgml('<TERM>', sub {
1006 output "\n" unless $newline_last++;
1009 push_output('string');
1011 sgml('</TERM>', sub {
1012 my $term = pop_output();
1019 sgml('<GLOSSTERM>', sub {
1020 output "\n" unless $newline_last++;
1023 push_output('string');
1025 sgml('</GLOSSTERM>', sub {
1026 my $term = pop_output();
1034 sgml('<LISTITEM>', sub {
1036 if($_[0]->in('ITEMIZEDLIST')) {
1037 output "\n" unless $newline_last++;
1038 output ".TP 0.2i\n\\(bu\n";
1042 # Assume Arabic numeration for now.
1043 elsif($_[0]->in('ORDEREDLIST')) {
1044 output "\n" unless $newline_last++;
1045 output ".TP 3\n", $_[0]->parent->ext->{'count'}++, ". \n";
1048 $_[0]->ext->{'nobreak'} = 1;
1050 sgml('<GLOSSDEF>', sub {
1051 $_[0]->ext->{'nobreak'} = 1;
1054 sgml('<SIMPLELIST>', sub {
1055 $_[0]->ext->{'first_member'} = 1;
1058 sgml('<MEMBER>', sub {
1059 my $parent = $_[0]->parent;
1061 if($parent->attribute('TYPE')->value =~ /Inline/i) {
1062 if($parent->ext->{'first_member'}) {
1063 # If this is the first member don't put any commas
1064 $parent->ext->{'first_member'} = 0;
1068 } elsif($parent->attribute('TYPE')->value =~ /Vert/i) {
1069 output "\n" unless $newline_last++;
1078 ########################################################################
1080 # Stuff we don't know how to handle (yet)
1082 ########################################################################
1106 ########################################################################
1108 # Linkage, cross references
1110 ########################################################################
1113 sgml('</ULINK>', sub {
1114 output ' <URL:', $_[0]->attribute('URL')->value, '>';
1118 # If cross reference target is a RefEntry,
1119 # output CiteRefEntry-style references.
1120 sgml('<XREF>', sub {
1121 my $id = $_[0]->attribute('LINKEND')->value;
1122 my $manref = $Refs->get("refentry:$id");
1125 my ($title, $sect) = ($manref =~ /(.*)(\(.*\))/);
1131 $blank_xrefs++ if $write_manpages;
1132 output "[XRef to $id]";
1143 ########################################################################
1147 ########################################################################
1149 man_sgml('|[lt ]|', '<');
1150 man_sgml('|[gt ]|', '>');
1151 man_sgml('|[amp ]|', '&');
1154 # Default handlers (uncomment these if needed). Right now, these are set
1155 # up to gag on any unrecognised elements, sdata, processing-instructions,
1158 # sgml('start_element',sub { die "Unknown element: " . $_[0]->name; });
1159 # sgml('end_element','');
1161 # This is for weeding out and escaping certain characters.
1162 # This looks like it's inefficient since it's done on every line, but
1163 # in reality, SGMLSpm and sgmlspl parsing ESIS takes _much_ longer.
1167 if(!$write_manpages) { return; }
1168 elsif($raw_cdata) { output $_[0]; return; }
1170 # Escape backslashes
1171 $_[0] =~ s/\\/\\\\/g;
1173 # In non-'pre'-type elements:
1174 if(!$nocollapse_whitespace) {
1175 # Change tabs to spaces
1178 # Do not allow indents at beginning of line
1179 # groff chokes on that.
1183 # If the line is all blank, don't do anything.
1184 if($_[0] eq '') { return; }
1186 $_[0] =~ s/^\./\\\&\./;
1188 # Argh... roff doesn't like ' either...
1189 $_[0] =~ s/^\'/\\\&\'/;
1199 # When in whitespace-collapsing mode, we disallow consecutive newlines.
1203 if($nocollapse_whitespace || !$newline_last) {
1212 if($_[0] =~ /\[minus \]/) { output "-"; }
1213 elsif($_[0] =~ /\[copy \]/) { output "(C)"; }
1214 elsif($_[0] =~ /\[nbsp \]/) { output " "; }
1215 else { die "Unknown SDATA: " . $_[0]; }
1217 sgml('pi',sub { die "Unknown processing instruction: " . $_[0]; });
1218 sgml('entity',sub { die "Unknown external entity: " . $_[0]->name; });
1219 sgml('start_subdoc',sub { die "Unknown subdoc entity: " . $_[0]->name; });
1220 sgml('end_subdoc','');
1221 sgml('conforming','');