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 2000/07/21 20:22:30 rosalia 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.
415 man_sgml('<PARAMDEF>', '(');
416 man_sgml('</PARAMDEF>', ");\n");
417 man_sgml('<VOID>', "(void);\n");
423 # my $choice = $_[0]->attribute('CHOICE')->value;
425 # The content model for CmdSynopsis doesn't include #PCDATA,
426 # so we won't see any of the whitespace in the source file,
427 # so we have to add it after each component.
430 if($_[0]->attribute('CHOICE')->value =~ /opt/i) {
438 if($_[0]->attribute('REP')->value =~ /^Repeat/i) {
443 if($_[0]->attribute('CHOICE')->value =~ /opt/i) {
448 sgml('<ARG>', \&arg_start);
449 sgml('</ARG>', \&arg_end);
450 sgml('<GROUP>', \&arg_start);
451 sgml('</GROUP>', \&arg_end);
453 sgml('<OPTION>', \&bold_on);
454 sgml('</OPTION>', \&font_off);
456 # FIXME: This is one _blank_ line.
457 man_sgml('<SBR>', "\n\n");
460 ########################################################################
464 ########################################################################
466 # The name of the section is handled by TITLE. This just sets
467 # up the roff markup.
468 man_sgml('<REFSECT1>', "\n.SH ");
469 man_sgml('<REFSECT2>', "\n.SS ");
470 man_sgml('<REFSECT3>', "\n.SS ");
473 ########################################################################
477 ########################################################################
479 sgml('<TITLE>', sub {
480 if($_[0]->in('REFERENCE') or $_[0]->in('BOOK')) {
485 sgml('</TITLE>', sub {
486 my $title = fold_string(pop_output());
489 if($_[0]->in('REFERENCE') or $_[0]->in('BOOK')) {
490 # We use TITLE of enclosing Reference or Book as manual name
491 $manpage_manual = $title;
494 elsif(exists $_[0]->parent->ext->{'title'}) {
495 # By far the easiest case. Just fold the string as
496 # above, and then set the parent element's variable.
497 $_[0]->parent->ext->{'title'} = $title;
500 # If the parent element's handlers are lazy,
501 # output the folded string for them :)
502 # We assume they want uppercase and a newline.
503 output '"', uc($title), "\"\n";
508 sgml('<ATTRIBUTION>', sub { push_output('string') });
509 sgml('</ATTRIBUTION>', sub { $_[0]->parent->ext->{'attribution'} = pop_output(); });
513 sgml('<DOCINFO>', sub { push_output('nul'); });
514 sgml('</DOCINFO>', sub { pop_output(); });
515 sgml('<REFSECT1INFO>', sub { push_output('nul'); });
516 sgml('</REFSECT1INFO>', sub { pop_output(); });
517 sgml('<REFSECT2INFO>', sub { push_output('nul'); });
518 sgml('</REFSECT2INFO>', sub { pop_output(); });
519 sgml('<REFSECT3INFO>', sub { push_output('nul'); });
520 sgml('</REFSECT3INFO>', sub { pop_output(); });
522 sgml('<INDEXTERM>', sub { push_output('nul'); });
523 sgml('</INDEXTERM>', sub { pop_output(); });
526 ########################################################################
528 # Set bold on enclosed content
530 ########################################################################
532 sgml('<APPLICATION>', \&bold_on); sgml('</APPLICATION>', \&font_off);
534 sgml('<CLASSNAME>', \&bold_on); sgml('</CLASSNAME>', \&font_off);
535 sgml('<STRUCTNANE>', \&bold_on); sgml('</STRUCTNAME>', \&font_off);
536 sgml('<STRUCTFIELD>', \&bold_on); sgml('</STRUCTFIELD>', \&font_off);
537 sgml('<SYMBOL>', \&bold_on); sgml('</SYMBOL>', \&font_off);
538 sgml('<TYPE>', \&bold_on); sgml('</TYPE>', \&font_off);
540 sgml('<ENVAR>', \&bold_on); sgml('</ENVAR>', \&font_off);
542 sgml('<FUNCTION>', \&bold_on); sgml('</FUNCTION>', \&font_off);
544 sgml('<EMPHASIS>', \&bold_on); sgml('</EMPHASIS>', \&font_off);
546 sgml('<ERRORNAME>', \&bold_on); sgml('</ERRORNAME>', \&font_off);
549 sgml('<COMMAND>', \&bold_on); sgml('</COMMAND>', \&font_off);
551 sgml('<GUIBUTTON>', \&bold_on); sgml('</GUIBUTTON>', \&font_off);
552 sgml('<GUIICON>', \&bold_on); sgml('</GUIICON>', \&font_off);
560 sgml('<ACCEL>', \&bold_on); sgml('</ACCEL>', \&font_off);
561 sgml('<KEYCAP>', \&bold_on); sgml('</KEYCAP>', \&font_off);
562 sgml('<KEYSYM>', \&bold_on); sgml('</KEYSYM>', \&font_off);
567 sgml('<USERINPUT>', \&bold_on); sgml('</USERINPUT>', \&font_off);
569 sgml('<INTERFACEDEFINITION>', \&bold_on);
570 sgml('</INTERFACEDEFINITION>', \&font_off);
572 # May need to look at the CLASS
573 sgml('<SYSTEMITEM>', \&bold_on);
574 sgml('</SYSTEMITEM>', \&font_off);
580 ########################################################################
582 # Set italic on enclosed content
584 ########################################################################
586 sgml('<FIRSTTERM>', \&italic_on); sgml('</FIRSTTERM>', \&font_off);
588 sgml('<FILENAME>', \&italic_on); sgml('</FILENAME>', \&font_off);
589 sgml('<PARAMETER>', \&italic_on); sgml('</PARAMETER>', \&font_off);
590 sgml('<PROPERTY>', \&italic_on); sgml('</PROPERTY>', \&font_off);
592 sgml('<REPLACEABLE>', sub {
594 if($_[0]->in('TOKEN')) {
595 # When tokenizing, follow more 'intuitive' convention
599 sgml('</REPLACEABLE>', sub {
600 if($_[0]->in('TOKEN')) {
606 sgml('<CITETITLE>', \&italic_on); sgml('</CITETITLE>', \&font_off);
607 sgml('<FOREIGNPHRASE>', \&italic_on); sgml('</FOREIGNPHRASE>', \&font_off);
609 sgml('<LINEANNOTATION>', \&italic_on); sgml('</LINEANNOTATION>', \&font_off);
616 ########################################################################
618 # Other 'inline' elements
620 ########################################################################
622 man_sgml('<EMAIL>', '<');
623 man_sgml('</EMAIL>', '>');
624 man_sgml('<OPTIONAL>', '[');
625 man_sgml('</OPTIONAL>', ']');
627 man_sgml('</TRADEMARK>', "\\u\\s-2TM\\s+2\\d");
629 man_sgml('<COMMENT>', "[Comment: ");
630 man_sgml('</COMMENT>', "]");
632 man_sgml('<QUOTE>', "``");
633 man_sgml('</QUOTE>', "''");
635 #man_sgml('<LITERAL>', '"');
636 #man_sgml('</LITERAL>', '"');
638 # No special presentation:
664 # There doesn't seem to be a good way to represent LITERAL in -man
668 ########################################################################
670 # Paragraph and paragraph-like elements
672 ########################################################################
675 output "\n" unless $newline_last++;
677 # In lists, etc., don't start paragraph with .PP since
678 # the indentation will be gone.
680 if($_[0]->parent->ext->{'nobreak'}==1) {
681 # Usually this is the FIRST element of
682 # a hanging tag, so we MUST not do a full
684 $_[0]->parent->ext->{'nobreak'} = 2;
685 } elsif($_[0]->parent->ext->{'nobreak'}==2) {
686 # Usually these are the NEXT elements of
687 # a hanging tag. If we break using a blank
691 # Normal case. (For indented blocks too, at least
692 # -man isn't so braindead in this area.)
696 # Actually applies to a few other block elements as well
698 output "\n" unless $newline_last++;
701 sgml('<PARA>', \¶_start);
702 sgml('</PARA>', \¶_end);
703 sgml('<SIMPARA>', \¶_start);
704 sgml('</SIMPARA>', \¶_end);
706 # Nothing special, except maybe FIXME set nobreak.
707 sgml('<INFORMALEXAMPLE>', \¶_start);
708 sgml('</INFORMALEXAMPLE>', \¶_end);
714 ########################################################################
716 # Blocks using SS sections
718 ########################################################################
720 # FIXME: We need to consider the effects of SS
721 # in a hanging tag :(
723 # Complete with the optional-title dilemma (again).
724 sgml('<ABSTRACT>', sub {
725 $_[0]->ext->{'title'} = 'ABSTRACT';
726 output "\n" unless $newline_last++;
727 push_output('string');
729 sgml('</ABSTRACT>', sub {
730 my $content = pop_output();
732 # As ABSTRACT is never on the same level as RefSect1,
733 # this leaves us with only .SS in terms of -man macros.
734 output ".SS \"", uc($_[0]->ext->{'title'}), "\"\n";
737 output "\n" unless $newline_last++;
740 # Ah, I needed a break. Example always has a title.
741 man_sgml('<EXAMPLE>', "\n.SS ");
742 sgml('</EXAMPLE>', \¶_end);
745 man_sgml('<SIDEBAR>', "\n.SS ");
746 sgml('</SIDEBAR>', \¶_end);
749 man_sgml('<HIGHLIGHTS>', "\n.SS HIGHLIGHTS\n");
750 sgml('</HIGHLIGHTS>', \¶_end);
755 ########################################################################
757 # Indented 'Block' elements
759 ########################################################################
761 sub indent_block_start
763 output "\n" unless $newline_last++;
768 output "\n" unless $newline_last++;
772 # This element is almost like an admonition (below),
773 # only the default title is blank :)
775 sgml('<BLOCKQUOTE>', sub {
776 $_[0]->ext->{'title'} = '';
777 output "\n" unless $newline_last++;
778 push_output('string');
780 sgml('</BLOCKQUOTE>', sub {
781 my $content = pop_output();
783 indent_block_start();
785 if($_[0]->ext->{'title'}) {
786 output ".B \"", $_[0]->ext->{'title'}, ":\"\n";
791 if($_[0]->ext->{'attribution'}) {
792 output "\n" unless $newline_last++;
793 # One place where roff's space-sensitivity makes sense :)
795 output $_[0]->ext->{'attribution'} . "\n";
801 # Set off admonitions from the rest of the text by indenting.
802 # FIXME: Need to check if this works inside paragraphs, not enclosing them.
804 my $content = pop_output();
806 indent_block_start();
808 # When the admonition is only one paragraph,
809 # it looks nicer if the title was inline.
811 while ($content =~ /^\.PP/gm) { $num_para++ }
813 $content =~ s/^\.PP\n//;
816 output ".B \"" . $_[0]->ext->{'title'} . ":\"\n";
823 # We can't see right now whether or not there is a TITLE
824 # element, so we have to save the output now and add it back
825 # at the end of this admonition.
826 $_[0]->ext->{'title'} = 'Note';
828 # Although admonition_end's indent_block_start will do this,
829 # we need to synchronize the output _now_
830 output "\n" unless $newline_last++;
832 push_output('string');
834 sgml('</NOTE>', \&admonition_end);
837 sgml('<WARNING>', sub {
838 $_[0]->ext->{'title'} = 'Warning';
839 output "\n" unless $newline_last++;
840 push_output('string');
842 sgml('</WARNING>', \&admonition_end);
845 $_[0]->ext->{'title'} = 'Tip';
846 output "\n" unless $newline_last++;
847 push_output('string');
849 sgml('</TIP>', \&admonition_end);
850 sgml('<CAUTION>', sub {
851 $_[0]->ext->{'title'} = 'Caution';
852 output "\n" unless $newline_last++;
853 push_output('string');
855 sgml('</CAUTION>', \&admonition_end);
857 sgml('<IMPORTANT>', sub {
858 $_[0]->ext->{'title'} = 'Important';
859 output "\n" unless $newline_last++;
860 push_output('string');
862 sgml('</IMPORTANT>', \&admonition_end);
875 ########################################################################
879 ########################################################################
882 output "\n" unless $newline_last++;
884 if($_[0]->parent->ext->{'nobreak'}==1) {
885 # Usually this is the FIRST element of
886 # a hanging tag, so we MUST not do a full
888 $_[0]->parent->ext->{'nobreak'} = 2;
893 output(".nf\n") unless $nocollapse_whitespace++;
897 output "\n" unless $newline_last++;
898 output(".fi\n") unless --$nocollapse_whitespace;
901 sgml('<PROGRAMLISTING>', \&verbatim_start);
902 sgml('</PROGRAMLISTING>', \&verbatim_end);
904 sgml('<SCREEN>', \&verbatim_start);
905 sgml('</SCREEN>', \&verbatim_end);
907 sgml('<LITERALLAYOUT>', \&verbatim_start);
908 sgml('</LITERALLAYOUT>', \&verbatim_end);
910 #sgml('<SYNOPSIS>', sub {
911 # if($_[0]->attribute('FORMAT')->value =~ /linespecific/i) {
918 #sgml('</SYNOPSIS>', sub {
919 # if($_[0]->attribute('FORMAT')->value =~ /linespecific/i) {
923 # roffcmd("");# not sure about this.
926 sgml('<SYNOPSIS>', \&verbatim_start);
927 sgml('</SYNOPSIS>', \&verbatim_end);
937 ########################################################################
941 ########################################################################
943 # Indent nested lists.
944 sub indent_list_start {
945 if($list_nestlevel++) {
946 output "\n" unless $newline_last++;
950 sub indent_list_end {
951 if(--$list_nestlevel) {
952 output "\n" unless $newline_last++;
957 sgml('<VARIABLELIST>', \&indent_list_start);
958 sgml('</VARIABLELIST>', \&indent_list_end);
959 sgml('<ITEMIZEDLIST>', \&indent_list_start);
960 sgml('</ITEMIZEDLIST>', \&indent_list_end);
961 sgml('<ORDEREDLIST>', sub {
963 $_[0]->ext->{'count'} = 1;
965 sgml('</ORDEREDLIST>', \&indent_list_end);
967 # Output content on one line, bolded.
969 output "\n" unless $newline_last++;
972 push_output('string');
974 sgml('</TERM>', sub {
975 my $term = pop_output();
983 sgml('<LISTITEM>', sub {
985 if($_[0]->in('ITEMIZEDLIST')) {
986 output "\n" unless $newline_last++;
987 output ".TP 0.2i\n\\(bu\n";
991 # Assume Arabic numeration for now.
992 elsif($_[0]->in('ORDEREDLIST')) {
993 output "\n" unless $newline_last++;
994 output ".TP ", $_[0]->parent->ext->{'count'}++, ". \n";
997 $_[0]->ext->{'nobreak'} = 1;
1000 sgml('<SIMPLELIST>', sub {
1001 $_[0]->ext->{'first_member'} = 1;
1004 sgml('<MEMBER>', sub {
1005 my $parent = $_[0]->parent;
1007 if($parent->attribute('TYPE')->value =~ /Inline/i) {
1008 if($parent->ext->{'first_member'}) {
1009 # If this is the first member don't put any commas
1010 $parent->ext->{'first_member'} = 0;
1014 } elsif($parent->attribute('TYPE')->value =~ /Vert/i) {
1015 output "\n" unless $newline_last++;
1024 ########################################################################
1026 # Stuff we don't know how to handle (yet)
1028 ########################################################################
1052 ########################################################################
1054 # Linkage, cross references
1056 ########################################################################
1059 sgml('</ULINK>', sub {
1060 # output ' <URL:', $_[0]->attribute('URL')->value, '>';
1064 # If cross reference target is a RefEntry,
1065 # output CiteRefEntry-style references.
1066 sgml('<XREF>', sub {
1067 my $id = $_[0]->attribute('LINKEND')->value;
1068 my $manref = $Refs->get("refentry:$id");
1071 my ($title, $sect) = ($manref =~ /(.*)(\(.*\))/);
1077 $blank_xrefs++ if $write_manpages;
1078 output "[XRef to $id]";
1089 ########################################################################
1093 ########################################################################
1095 man_sgml('|[lt ]|', '<');
1096 man_sgml('|[gt ]|', '>');
1097 man_sgml('|[amp ]|', '&');
1100 # Default handlers (uncomment these if needed). Right now, these are set
1101 # up to gag on any unrecognised elements, sdata, processing-instructions,
1104 # sgml('start_element',sub { die "Unknown element: " . $_[0]->name; });
1105 # sgml('end_element','');
1107 # This is for weeding out and escaping certain characters.
1108 # This looks like it's inefficient since it's done on every line, but
1109 # in reality, SGMLSpm and sgmlspl parsing ESIS takes _much_ longer.
1113 if(!$write_manpages) { return; }
1114 elsif($raw_cdata) { output $_[0]; return; }
1116 # Escape backslashes
1117 $_[0] =~ s/\\/\\\\/g;
1119 # In non-'pre'-type elements:
1120 if(!$nocollapse_whitespace) {
1121 # Change tabs to spaces
1124 # Do not allow indents at beginning of line
1125 # groff chokes on that.
1129 # If the line is all blank, don't do anything.
1130 if($_[0] eq '') { return; }
1132 $_[0] =~ s/^\./\\\&\./;
1134 # Argh... roff doesn't like ' either...
1135 $_[0] =~ s/^\'/\\\&\'/;
1145 # When in whitespace-collapsing mode, we disallow consecutive newlines.
1149 if($nocollapse_whitespace || !$newline_last) {
1156 sgml('sdata',sub { die "Unknown SDATA: " . $_[0]; });
1157 sgml('pi',sub { die "Unknown processing instruction: " . $_[0]; });
1158 sgml('entity',sub { die "Unknown external entity: " . $_[0]->name; });
1159 sgml('start_subdoc',sub { die "Unknown subdoc entity: " . $_[0]->name; });
1160 sgml('end_subdoc','');
1161 sgml('conforming','');