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.4 2006/07/18 14:49:14 david__schmidt 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 generated by docbook2man-spec.pl
263 .\\" (included in the Privoxy source tarball) from a DocBook document.
266 my $manpage_date = `date "+%d %B %Y"`;
270 # If the title is not mixed-case, convention says to
271 # uppercase the whole title. (The canonical title is
273 if($manpage_title =~ /[A-Z]/) {
274 output fold_string($manpage_title);
276 output uc(fold_string($manpage_title));
279 output '" "', fold_string($manpage_sect),
280 '" "', fold_string(`date "+%d %B %Y"`),
281 '" "', $manpage_misc,
282 '" "', $manpage_manual,
287 # References to this RefEntry.
288 my $id = $_[0]->parent->attribute('ID')->value;
290 # The 'package name' part of the section should
291 # not be used when citing it.
292 my ($sectnum) = ($manpage_sect =~ /([0-9]*)/);
294 if($_[0]->parent->attribute('XREFLABEL')->value eq '') {
295 $Refs->put("refentry:$id", "$manpage_title($sectnum)");
297 $Refs->put("refentry:$id",
298 $_[0]->parent->attribute('XREFLABEL')->value .
304 sgml('<REFENTRYTITLE>', sub {
305 if($_[0]->in('REFMETA')) {
308 # Manpage citations are in bold.
312 sgml('</REFENTRYTITLE>', sub {
313 if($_[0]->in('REFMETA')) {
315 $manpage_title = pop_output();
320 sgml('<MANVOLNUM>', sub {
321 if($_[0]->in('REFMETA')) {
324 # Manpage citations use ().
328 sgml('</MANVOLNUM>', sub {
329 if($_[0]->in('REFMETA')) {
331 $manpage_sect = pop_output();
336 sgml('<REFMISCINFO>', \&save_cdata);
337 sgml('</REFMISCINFO>', sub {
339 $manpage_misc = fold_string(pop_output());
344 man_sgml('<REFNAMEDIV>', "\n.SH NAME\n");
346 sgml('<REFNAME>', \&save_cdata);
347 sgml('</REFNAME>', sub {
349 push(@manpage_names, pop_output());
352 sgml('<REFPURPOSE>', \&save_cdata);
353 sgml('</REFPURPOSE>', sub {
355 my $manpage_purpose = fold_string(pop_output());
357 for(my $i = 0; $i < $#manpage_names; $i++) {
358 output fold_string($manpage_names[$i]), ', ';
361 output fold_string($manpage_names[$#manpage_names]);
362 output " \\- $manpage_purpose\n";
366 foreach(@manpage_names) {
367 # Don't link to itself
368 if($_ ne $manpage_title) {
369 print LINKSFILE "$manpage_title.$manpage_sect $_.$manpage_sect\n";
374 man_sgml('<REFCLASS>', "\n.sp\n");
382 ########################################################################
384 # SYNOPSIS section and synopses
386 ########################################################################
388 man_sgml('<REFSYNOPSISDIV>', "\n.SH SYNOPSIS\n");
389 man_sgml('</REFSYNOPSISDIV>', "\n");
391 ## FIXME! Must be made into block elements!!
392 #sgml('<FUNCSYNOPSIS>', \&bold_on);
393 #sgml('</FUNCSYNOPSIS>', \&font_off);
394 #sgml('<CMDSYNOPSIS>', \&bold_on);
395 #sgml('</CMDSYNOPSIS>', \&font_off);
397 man_sgml('<FUNCSYNOPSIS>', sub {
398 man_output("\n.sp\n");
401 man_sgml('</FUNCSYNOPSIS>', sub {
406 man_sgml('<CMDSYNOPSIS>', "\n\n");
407 man_sgml('</CMDSYNOPSIS>', "\n\n");
409 man_sgml('<FUNCPROTOTYPE>', "\n.sp\n");
411 # Arguments to functions. This is C convention.
414 if($_[0]->parent->ext->{'inparams'}) {
418 $_[0]->parent->ext->{'inparams'} = 1;
421 man_sgml('<PARAMDEF>', \¶mdef);
422 man_sgml('</FUNCPROTOTYPE>', ");\n");
423 man_sgml('<VOID>', "(void");
424 man_sgml('<VARARGS>', "(...");
430 if(not $_[0]->parent->in('TERM')) {
431 if($_[0]->attribute('CHOICE')->value =~ /opt/i) {
433 } elsif($_[0]->attribute('CHOICE')->value =~ /req/i) {
437 $_[0]->ext->{'count'} = 1;
441 if($_[0]->attribute('REP')->value =~ /^Repeat/i) {
446 if(not $_[0]->parent->in('TERM')) {
447 if($_[0]->attribute('CHOICE')->value =~ /opt/i) {
449 } elsif($_[0]->attribute('CHOICE')->value =~ /req/i) {
457 # my $choice = $_[0]->attribute('CHOICE')->value;
459 # The content model for CmdSynopsis doesn't include #PCDATA,
460 # so we won't see any of the whitespace in the source file,
461 # so we have to add it after each component.
464 if($_[0]->in('GROUP')) {
465 output '| ' if $_[0]->parent->ext->{'count'} > 1;
466 $_[0]->parent->ext->{'count'}++;
467 } elsif($_[0]->attribute('CHOICE')->value =~ /opt/i) {
475 if($_[0]->attribute('REP')->value =~ /^Repeat/i) {
480 if($_[0]->attribute('CHOICE')->value =~ /opt/i and
481 not $_[0]->in('GROUP')) {
486 sgml('<ARG>', \&arg_start);
487 sgml('</ARG>', \&arg_end);
488 sgml('<GROUP>', \&group_start);
489 sgml('</GROUP>', \&group_end);
491 sgml('<OPTION>', \&bold_on);
492 sgml('</OPTION>', \&font_off);
494 man_sgml('<SBR>', "\n ");
497 ########################################################################
501 ########################################################################
503 # The name of the section is handled by TITLE. This just sets
504 # up the roff markup.
505 man_sgml('<REFSECT1>', "\n.SH ");
506 man_sgml('<REFSECT2>', "\n.SS ");
507 man_sgml('<REFSECT3>', "\n.SS ");
510 ########################################################################
514 ########################################################################
516 sgml('<TITLE>', sub {
517 if($_[0]->in('REFERENCE') or $_[0]->in('BOOK')) {
522 sgml('</TITLE>', sub {
523 my $title = fold_string(pop_output());
526 if($_[0]->in('REFERENCE') or $_[0]->in('BOOK')) {
527 # We use TITLE of enclosing Reference or Book as manual name
528 $manpage_manual = $title;
531 elsif(exists $_[0]->parent->ext->{'title'}) {
532 # By far the easiest case. Just fold the string as
533 # above, and then set the parent element's variable.
534 $_[0]->parent->ext->{'title'} = $title;
537 # If the parent element's handlers are lazy,
538 # output the folded string for them :)
539 # We assume they want uppercase and a newline.
540 output '"', uc($title), "\"\n";
545 sgml('<ATTRIBUTION>', sub { push_output('string') });
546 sgml('</ATTRIBUTION>', sub { $_[0]->parent->ext->{'attribution'} = pop_output(); });
550 sgml('<DOCINFO>', sub { push_output('nul'); });
551 sgml('</DOCINFO>', sub { pop_output(); });
552 sgml('<REFSECT1INFO>', sub { push_output('nul'); });
553 sgml('</REFSECT1INFO>', sub { pop_output(); });
554 sgml('<REFSECT2INFO>', sub { push_output('nul'); });
555 sgml('</REFSECT2INFO>', sub { pop_output(); });
556 sgml('<REFSECT3INFO>', sub { push_output('nul'); });
557 sgml('</REFSECT3INFO>', sub { pop_output(); });
559 sgml('<INDEXTERM>', sub { push_output('nul'); });
560 sgml('</INDEXTERM>', sub { pop_output(); });
563 ########################################################################
565 # Set bold on enclosed content
567 ########################################################################
569 sgml('<APPLICATION>', \&bold_on); sgml('</APPLICATION>', \&font_off);
571 sgml('<CLASSNAME>', \&bold_on); sgml('</CLASSNAME>', \&font_off);
572 sgml('<STRUCTNANE>', \&bold_on); sgml('</STRUCTNAME>', \&font_off);
573 sgml('<STRUCTFIELD>', \&bold_on); sgml('</STRUCTFIELD>', \&font_off);
574 sgml('<SYMBOL>', \&bold_on); sgml('</SYMBOL>', \&font_off);
575 sgml('<TYPE>', \&bold_on); sgml('</TYPE>', \&font_off);
577 sgml('<ENVAR>', \&bold_on); sgml('</ENVAR>', \&font_off);
579 sgml('<FUNCTION>', \&bold_on); sgml('</FUNCTION>', \&font_off);
581 sgml('<EMPHASIS>', \&bold_on); sgml('</EMPHASIS>', \&font_off);
583 sgml('<ERRORNAME>', \&bold_on); sgml('</ERRORNAME>', \&font_off);
586 sgml('<COMMAND>', \&bold_on); sgml('</COMMAND>', \&font_off);
588 sgml('<GUIBUTTON>', \&bold_on); sgml('</GUIBUTTON>', \&font_off);
589 sgml('<GUIICON>', \&bold_on); sgml('</GUIICON>', \&font_off);
597 sgml('<ACCEL>', \&bold_on); sgml('</ACCEL>', \&font_off);
598 sgml('<KEYCAP>', \&bold_on); sgml('</KEYCAP>', \&font_off);
599 sgml('<KEYSYM>', \&bold_on); sgml('</KEYSYM>', \&font_off);
604 sgml('<USERINPUT>', \&bold_on); sgml('</USERINPUT>', \&font_off);
606 sgml('<INTERFACEDEFINITION>', \&bold_on);
607 sgml('</INTERFACEDEFINITION>', \&font_off);
609 # May need to look at the CLASS
610 sgml('<SYSTEMITEM>', \&bold_on);
611 sgml('</SYSTEMITEM>', \&font_off);
617 ########################################################################
619 # Set italic on enclosed content
621 ########################################################################
623 sgml('<FIRSTTERM>', \&italic_on); sgml('</FIRSTTERM>', \&font_off);
625 sgml('<FILENAME>', \&italic_on); sgml('</FILENAME>', \&font_off);
626 sgml('<PARAMETER>', \&italic_on); sgml('</PARAMETER>', \&font_off);
627 sgml('<PROPERTY>', \&italic_on); sgml('</PROPERTY>', \&font_off);
629 sgml('<REPLACEABLE>', sub {
631 if($_[0]->in('TOKEN')) {
632 # When tokenizing, follow more 'intuitive' convention
636 sgml('</REPLACEABLE>', sub {
637 if($_[0]->in('TOKEN')) {
643 sgml('<CITETITLE>', \&italic_on); sgml('</CITETITLE>', \&font_off);
644 sgml('<FOREIGNPHRASE>', \&italic_on); sgml('</FOREIGNPHRASE>', \&font_off);
646 sgml('<LINEANNOTATION>', \&italic_on); sgml('</LINEANNOTATION>', \&font_off);
653 ########################################################################
655 # Other 'inline' elements
657 ########################################################################
659 man_sgml('<EMAIL>', '<');
660 man_sgml('</EMAIL>', '>');
661 man_sgml('<OPTIONAL>', '[');
662 man_sgml('</OPTIONAL>', ']');
664 man_sgml('</TRADEMARK>', "\\u\\s-2TM\\s+2\\d");
666 man_sgml('<COMMENT>', "[Comment: ");
667 man_sgml('</COMMENT>', "]");
669 man_sgml('<QUOTE>', "``");
670 man_sgml('</QUOTE>', "''");
672 #man_sgml('<LITERAL>', '"');
673 #man_sgml('</LITERAL>', '"');
675 # No special presentation:
701 # There doesn't seem to be a good way to represent LITERAL in -man
705 ########################################################################
707 # Paragraph and paragraph-like elements
709 ########################################################################
712 output "\n" unless $newline_last++;
714 # In lists, etc., don't start paragraph with .PP since
715 # the indentation will be gone.
717 if($_[0]->parent->ext->{'nobreak'}==1) {
718 # Usually this is the FIRST element of
719 # a hanging tag, so we MUST not do a full
721 $_[0]->parent->ext->{'nobreak'} = 2;
722 } elsif($_[0]->parent->ext->{'nobreak'}==2) {
723 # Usually these are the NEXT elements of
724 # a hanging tag. If we break using a blank
728 # Normal case. (For indented blocks too, at least
729 # -man isn't so braindead in this area.)
733 # Actually applies to a few other block elements as well
735 output "\n" unless $newline_last++;
738 sgml('<PARA>', \¶_start);
739 sgml('</PARA>', \¶_end);
740 sgml('<SIMPARA>', \¶_start);
741 sgml('</SIMPARA>', \¶_end);
743 # Nothing special, except maybe FIXME set nobreak.
744 sgml('<INFORMALEXAMPLE>', \¶_start);
745 sgml('</INFORMALEXAMPLE>', \¶_end);
751 ########################################################################
753 # Blocks using SS sections
755 ########################################################################
757 # FIXME: We need to consider the effects of SS
758 # in a hanging tag :(
760 # Complete with the optional-title dilemma (again).
761 sgml('<ABSTRACT>', sub {
762 $_[0]->ext->{'title'} = 'ABSTRACT';
763 output "\n" unless $newline_last++;
764 push_output('string');
766 sgml('</ABSTRACT>', sub {
767 my $content = pop_output();
769 # As ABSTRACT is never on the same level as RefSect1,
770 # this leaves us with only .SS in terms of -man macros.
771 output ".SS \"", uc($_[0]->ext->{'title'}), "\"\n";
774 output "\n" unless $newline_last++;
777 # Ah, I needed a break. Example always has a title.
778 man_sgml('<EXAMPLE>', "\n.SS ");
779 sgml('</EXAMPLE>', \¶_end);
782 man_sgml('<SIDEBAR>', "\n.SS ");
783 sgml('</SIDEBAR>', \¶_end);
786 man_sgml('<HIGHLIGHTS>', "\n.SS HIGHLIGHTS\n");
787 sgml('</HIGHLIGHTS>', \¶_end);
792 ########################################################################
794 # Indented 'Block' elements
796 ########################################################################
798 sub indent_block_start
800 output "\n" unless $newline_last++;
805 output "\n" unless $newline_last++;
809 # This element is almost like an admonition (below),
810 # only the default title is blank :)
812 sgml('<BLOCKQUOTE>', sub {
813 $_[0]->ext->{'title'} = '';
814 output "\n" unless $newline_last++;
815 push_output('string');
817 sgml('</BLOCKQUOTE>', sub {
818 my $content = pop_output();
820 indent_block_start();
822 if($_[0]->ext->{'title'}) {
823 output ".B \"", $_[0]->ext->{'title'}, ":\"\n";
828 if($_[0]->ext->{'attribution'}) {
829 output "\n" unless $newline_last++;
830 # One place where roff's space-sensitivity makes sense :)
832 output $_[0]->ext->{'attribution'} . "\n";
838 # Set off admonitions from the rest of the text by indenting.
839 # FIXME: Need to check if this works inside paragraphs, not enclosing them.
841 my $content = pop_output();
843 indent_block_start();
845 # When the admonition is only one paragraph,
846 # it looks nicer if the title was inline.
848 while ($content =~ /^\.PP/gm) { $num_para++ }
850 $content =~ s/^\.PP\n//;
853 output ".B \"" . $_[0]->ext->{'title'} . ":\"\n";
860 # We can't see right now whether or not there is a TITLE
861 # element, so we have to save the output now and add it back
862 # at the end of this admonition.
863 $_[0]->ext->{'title'} = 'Note';
865 # Although admonition_end's indent_block_start will do this,
866 # we need to synchronize the output _now_
867 output "\n" unless $newline_last++;
869 push_output('string');
871 sgml('</NOTE>', \&admonition_end);
874 sgml('<WARNING>', sub {
875 $_[0]->ext->{'title'} = 'Warning';
876 output "\n" unless $newline_last++;
877 push_output('string');
879 sgml('</WARNING>', \&admonition_end);
882 $_[0]->ext->{'title'} = 'Tip';
883 output "\n" unless $newline_last++;
884 push_output('string');
886 sgml('</TIP>', \&admonition_end);
887 sgml('<CAUTION>', sub {
888 $_[0]->ext->{'title'} = 'Caution';
889 output "\n" unless $newline_last++;
890 push_output('string');
892 sgml('</CAUTION>', \&admonition_end);
894 sgml('<IMPORTANT>', sub {
895 $_[0]->ext->{'title'} = 'Important';
896 output "\n" unless $newline_last++;
897 push_output('string');
899 sgml('</IMPORTANT>', \&admonition_end);
912 ########################################################################
916 ########################################################################
919 output "\n" unless $newline_last++;
921 if($_[0]->parent->ext->{'nobreak'}==1) {
922 # Usually this is the FIRST element of
923 # a hanging tag, so we MUST not do a full
925 $_[0]->parent->ext->{'nobreak'} = 2;
930 output(".nf\n") unless $nocollapse_whitespace++;
934 output "\n" unless $newline_last++;
935 output(".fi\n") unless --$nocollapse_whitespace;
938 sgml('<PROGRAMLISTING>', \&verbatim_start);
939 sgml('</PROGRAMLISTING>', \&verbatim_end);
941 sgml('<SCREEN>', \&verbatim_start);
942 sgml('</SCREEN>', \&verbatim_end);
944 sgml('<LITERALLAYOUT>', \&verbatim_start);
945 sgml('</LITERALLAYOUT>', \&verbatim_end);
947 #sgml('<SYNOPSIS>', sub {
948 # if($_[0]->attribute('FORMAT')->value =~ /linespecific/i) {
955 #sgml('</SYNOPSIS>', sub {
956 # if($_[0]->attribute('FORMAT')->value =~ /linespecific/i) {
960 # roffcmd("");# not sure about this.
963 sgml('<SYNOPSIS>', \&verbatim_start);
964 sgml('</SYNOPSIS>', \&verbatim_end);
974 ########################################################################
978 ########################################################################
980 # Indent nested lists.
981 sub indent_list_start {
982 if($list_nestlevel++) {
983 output "\n" unless $newline_last++;
987 sub indent_list_end {
988 if(--$list_nestlevel) {
989 output "\n" unless $newline_last++;
994 sgml('<VARIABLELIST>', \&indent_list_start);
995 sgml('</VARIABLELIST>', \&indent_list_end);
996 sgml('<ITEMIZEDLIST>', \&indent_list_start);
997 sgml('</ITEMIZEDLIST>', \&indent_list_end);
998 sgml('<ORDEREDLIST>', sub {
1000 $_[0]->ext->{'count'} = 1;
1002 sgml('</ORDEREDLIST>', \&indent_list_end);
1003 sgml('<GLOSSLIST>', \&indent_list_start);
1004 sgml('</GLOSSLIST>', \&indent_list_end);
1006 # Output content on one line, bolded.
1007 sgml('<TERM>', sub {
1008 output "\n" unless $newline_last++;
1011 push_output('string');
1013 sgml('</TERM>', sub {
1014 my $term = pop_output();
1021 sgml('<GLOSSTERM>', sub {
1022 output "\n" unless $newline_last++;
1025 push_output('string');
1027 sgml('</GLOSSTERM>', sub {
1028 my $term = pop_output();
1036 sgml('<LISTITEM>', sub {
1038 if($_[0]->in('ITEMIZEDLIST')) {
1039 output "\n" unless $newline_last++;
1040 output ".TP 0.2i\n\\(bu\n";
1044 # Assume Arabic numeration for now.
1045 elsif($_[0]->in('ORDEREDLIST')) {
1046 output "\n" unless $newline_last++;
1047 output ".TP 3\n", $_[0]->parent->ext->{'count'}++, ". \n";
1050 $_[0]->ext->{'nobreak'} = 1;
1052 sgml('<GLOSSDEF>', sub {
1053 $_[0]->ext->{'nobreak'} = 1;
1056 sgml('<SIMPLELIST>', sub {
1057 $_[0]->ext->{'first_member'} = 1;
1060 sgml('<MEMBER>', sub {
1061 my $parent = $_[0]->parent;
1063 if($parent->attribute('TYPE')->value =~ /Inline/i) {
1064 if($parent->ext->{'first_member'}) {
1065 # If this is the first member don't put any commas
1066 $parent->ext->{'first_member'} = 0;
1070 } elsif($parent->attribute('TYPE')->value =~ /Vert/i) {
1071 output "\n" unless $newline_last++;
1080 ########################################################################
1082 # Stuff we don't know how to handle (yet)
1084 ########################################################################
1108 ########################################################################
1110 # Linkage, cross references
1112 ########################################################################
1115 sgml('</ULINK>', sub {
1116 output ' <URL:', $_[0]->attribute('URL')->value, '>';
1120 # If cross reference target is a RefEntry,
1121 # output CiteRefEntry-style references.
1122 sgml('<XREF>', sub {
1123 my $id = $_[0]->attribute('LINKEND')->value;
1124 my $manref = $Refs->get("refentry:$id");
1127 my ($title, $sect) = ($manref =~ /(.*)(\(.*\))/);
1133 $blank_xrefs++ if $write_manpages;
1134 output "[XRef to $id]";
1145 ########################################################################
1149 ########################################################################
1151 man_sgml('|[lt ]|', '<');
1152 man_sgml('|[gt ]|', '>');
1153 man_sgml('|[amp ]|', '&');
1156 # Default handlers (uncomment these if needed). Right now, these are set
1157 # up to gag on any unrecognised elements, sdata, processing-instructions,
1160 # sgml('start_element',sub { die "Unknown element: " . $_[0]->name; });
1161 # sgml('end_element','');
1163 # This is for weeding out and escaping certain characters.
1164 # This looks like it's inefficient since it's done on every line, but
1165 # in reality, SGMLSpm and sgmlspl parsing ESIS takes _much_ longer.
1169 if(!$write_manpages) { return; }
1170 elsif($raw_cdata) { output $_[0]; return; }
1172 # Escape backslashes
1173 $_[0] =~ s/\\/\\\\/g;
1175 # In non-'pre'-type elements:
1176 if(!$nocollapse_whitespace) {
1177 # Change tabs to spaces
1180 # Do not allow indents at beginning of line
1181 # groff chokes on that.
1185 # If the line is all blank, don't do anything.
1186 if($_[0] eq '') { return; }
1188 $_[0] =~ s/^\./\\\&\./;
1190 # Argh... roff doesn't like ' either...
1191 $_[0] =~ s/^\'/\\\&\'/;
1201 # When in whitespace-collapsing mode, we disallow consecutive newlines.
1205 if($nocollapse_whitespace || !$newline_last) {
1214 if($_[0] =~ /\[minus \]/) { output "-"; }
1215 elsif($_[0] =~ /\[copy \]/) { output "(C)"; }
1216 elsif($_[0] =~ /\[nbsp \]/) { output " "; }
1217 else { die "Unknown SDATA: " . $_[0]; }
1219 sgml('pi',sub { die "Unknown processing instruction: " . $_[0]; });
1220 sgml('entity',sub { die "Unknown external entity: " . $_[0]->name; });
1221 sgml('start_subdoc',sub { die "Unknown subdoc entity: " . $_[0]->name; });
1222 sgml('end_subdoc','');
1223 sgml('conforming','');