Ticket #36354: docbook2man-spec.pl

File docbook2man-spec.pl, 38.6 KB (added by lockhart (Thomas Lockhart), 12 years ago)

Patchfile from Fedora 18 RPM.

Line 
1=head1 NAME
2
3docbook2man-spec.pl - convert DocBook RefEntries to Unix manpages
4
5=head1 SYNOPSIS
6
7The sgmlspl script from the SGMLSpm Perl module must be used to run
8this script.  Use it like this:
9
10nsgmls some-docbook-document.sgml | sgmlspl docbook2man-spec.pl
11
12See man page or included DocBook documentation for details.
13
14=head1 DESCRIPTION
15
16This is a sgmlspl spec file that produces Unix-style
17man pages from DocBook RefEntry markup.
18
19=head1 COPYRIGHT
20
21Copyright (C) 1998-2001 Steve Cheng <stevecheng@users.sourceforge.net>
22
23Copyright (C) 1999 Thomas Lockhart <lockhart@alumni.caltech.edu>
24
25This program is free software; you can redistribute it and/or modify it
26under the terms of the GNU General Public License as published by the Free
27Software Foundation; either version 2, or (at your option) any later
28version.
29
30You should have received a copy of the GNU General Public License along with
31this program; see the file COPYING.  If not, please write to the Free
32Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
33
34=cut
35
36# $Id: docbook2man-spec.pl,v 1.11 2010/10/04 10:23:31 ovasik Exp $
37
38use SGMLS;                      # Use the SGMLS package.
39use SGMLS::Output;              # Use stack-based output.
40use SGMLS::Refs;
41
42
43########################################################################
44# SGMLSPL script produced automatically by the script sgmlspl.pl
45#
46# Document Type: any, but processes only RefEntries
47# Edited by: me :)
48########################################################################
49
50
51$write_manpages = 0;
52$blank_xrefs = 0;
53
54$default_sect = "1";
55$default_date = `date "+%d %B %Y"`;
56$cite_numeral_only = 1;
57
58while (@ARGV) {
59        my $arg = shift @ARGV;
60        if ($arg eq "--section") {
61                $default_sect = shift @ARGV || die "$arg requires an argument\n";
62        } elsif ($arg eq "--date") {
63                $default_date = shift @ARGV || die "$arg requires an argument\n";
64        } elsif ($arg eq "--lowercase") {
65                $lowercase_names = 1;
66        } elsif ($arg eq "--preserve-case") {
67                $lowercase_names = 0;
68        } elsif ($arg eq "--cite-numeral-only") {
69                $cite_numeral_only = 1;
70        } elsif ($arg eq "--nocite-numeral-only") {
71                $cite_numeral_only = 0;
72        } elsif ($arg eq "--help") {
73                print "Usage: $0",
74                        " [ --section <label> ]",
75                        " [ --date <string> ]",
76                        " [ --lowercase | --preserve-case ]",
77                        " [ --cite-numeral-only | --nocite-numeral-only ]",
78                        "\n";
79                exit;
80        } else {
81                die "unrecognized switch $arg; try $0 --help\n";
82        }
83}
84
85sgml('start', sub { 
86        push_output('nul');
87        $raw_cdata = 1;                 # Makes it a bit faster.
88       
89        # Links file
90        open(LINKSFILE, ">manpage.links");
91
92        $Refs = new SGMLS::Refs("manpage.refs", "manpage.log");
93});
94sgml('end', sub {
95        close(LINKSFILE);
96
97        # Explicitly invoke destructor,
98        # otherwise cache file may not get written!
99        # Thomas Lockhart, 1999-08-03, perl-5.004, RedHat5.2
100        undef $Refs;
101
102        if($blank_xrefs) {
103                warn "Warning: output contains unresolved XRefs\n";
104        }
105});
106
107
108########################################################################
109#
110# Output helpers
111#
112########################################################################
113
114# Remove leading and trailing blanks.
115
116sub StripString
117{
118        my $str = shift;
119
120        $str = $1 if ($str =~ m#^\s*(\S.*)#);
121        $str = $1 if ($str =~ m#^(.*\S)\s*$#);
122
123        return $str;
124}
125
126# Generate a good file name, for given manpage title and manvolnum
127# (cdata content).
128# Cleanup whitespace and convert to lower case if required.
129
130sub FileInfo
131{
132        my $title = StripString(shift);
133        my $volnum = StripString(shift);
134
135        $title = lc $title if $lowercase_names;
136
137        $title =~ tr/ /_/;
138        $volnum =~ tr/ /_/;
139
140        my $sectcite = $volnum;
141        # The 'package name' part of the section should
142        # not be used when citing it.
143        if ($cite_numeral_only) {
144                $sectcite = $1 if ($volnum =~ /^([0-9]+)/);
145        }
146       
147        return ("$title.$volnum", "$title($sectcite)");
148}
149
150# Our own version of sgml() and output() to allow simple string output
151# to play well with roff's stupid whitespace rules.
152
153sub man_sgml
154{
155        if(ref($_[1]) eq 'CODE') {
156                return &sgml;
157        }
158       
159        my $s = $_[1];
160        $s =~ s/\\/\\\\/g;
161        $s =~ s/'/\\'/g;
162
163        sgml($_[0], eval("sub { man_output '$s' }"));
164}
165
166sub man_output
167{
168        if($separator eq 'full') {
169                output "\n" unless $newline_last++;
170                output ".PP\n";
171                $separator = '';
172        }
173       
174        $_ = shift;
175        if(s/^\n//) {
176                output "\n" unless $newline_last++;
177        }
178        return if $_ eq '';
179       
180        output $_;
181
182        if(@_) {
183                output @_;
184                $newline_last = (pop(@_) =~ /\n$/);
185        } else {
186                $newline_last = ($_ =~ /\n$/)
187        }
188}
189
190# Fold lines into one, quote some characters
191sub fold_string
192{
193        $_ = shift;
194       
195        s/\\/\\\\/g;
196        s/"/""/g;
197
198        # Change tabs and newlines to spaces
199        # The newlines will be swallowed later while trimming
200        tr/[\t\n]/  /;
201
202        # Trim whitespace from beginning and end.
203        s/^ +//;
204        s/ +$//;
205
206        return $_;
207}
208       
209sub save_cdata()
210{
211        $raw_cdata++;
212        push_output('string');
213}
214
215sub bold_on()
216{
217        # If the last font is also bold, don't change anything.
218        # Basically this is to just get more readable man output.
219        if($fontstack[$#fontstack] ne 'bold') {
220                if(!$raw_cdata) {
221                        output '\fB';
222                        #$newline_last = 0;
223                }
224        }
225        push(@fontstack, 'bold');
226}
227
228sub italic_on()
229{
230        # If the last font is also italic, don't change anything.
231        if($fontstack[$#fontstack] ne 'italic') {
232                if(!$raw_cdata) {
233                        output '\fI';
234                        #$newline_last = 0;
235                }
236        }
237        push(@fontstack, 'italic');
238}
239
240sub font_off()
241{
242        my $thisfont = pop(@fontstack);
243        my $lastfont = $fontstack[$#fontstack];
244       
245        # Only output font change if it is different
246        if($thisfont ne $lastfont) {
247                if($raw_cdata)                  { return; }
248                elsif($lastfont eq 'bold')      { output '\fB'; }
249                elsif($lastfont eq 'italic')    { output '\fI'; }
250                else                            { output '\fR'; }
251       
252                #$newline_last = 0;
253        }
254}
255
256
257########################################################################
258#
259# Manpage management
260#
261########################################################################
262
263sgml('<REFENTRY>', sub { 
264        # This will be overwritten at end of REFMETA, when we know the name of the page.
265        pop_output();
266       
267        $write_manpages = 1;            # Currently writing manpage.
268       
269        $nocollapse_whitespace = 0;     # Current whitespace collapse counter.
270        $newline_last = 1;              # At beginning of line?
271                # Just a bit of warning, you will see this variable manipulated
272                # manually a lot.  It makes the code harder to follow but it
273                # saves you from having to worry about collapsing at the end of
274                # parse, stopping at verbatims, etc.
275        $raw_cdata = 0;                 # Instructs certain output functions to
276                                        # leave CDATA alone, so we can assign
277                                        # it to a string and process it, etc.
278        @fontstack = ();                # Fonts being activated.
279       
280        $list_nestlevel = 0;            # Indent certain nested content.
281
282        # Separator to use between 'elements' in the content of a
283        # paragraph (usually).  This makes sure that PCDATA after a list
284        # in a PARA gets a break in between and not become part of the
285        # last listitem.  Note that we can't do it after the list ends,
286        # because often the list ends the paragraph and we'll get an
287        # extra break.  Anything that changes the separator status from
288        # the default should also save its last state in the parent
289        # element's ext, but I'm not going to explain further.  It's a
290        # gross hack and almost guaranteed to fail in unforseen cases.
291        # The only way to avoid all this is to use a tree/grove model, which
292        # we're _not_ doing.
293        $separator = '';
294       
295        $manpage_title = '';            # Needed for indexing.
296        $manpage_sect = '';
297        @manpage_names = ();
298       
299        $manpage_misc = '';
300
301        # check refentry's language
302        if(defined($_[0]->attribute('LANG')->value)) {
303          $manpage_lang = $_[0]->attribute('LANG')->value;
304        }
305        else {
306          $manpage_lang = '';
307        }
308});
309sgml('</REFENTRY>', sub {
310        if(!$newline_last) {
311                output "\n";
312        }
313       
314        $raw_cdata = 1;
315        push_output('nul');
316
317        $write_manpages = 0;
318});
319
320sgml('</REFMETA>', sub {
321        my ($filename, $citation) = 
322                FileInfo($manpage_title, $manpage_sect || $default_sect);
323
324        push_output('file', $filename);
325
326        output <<'_END_BANNER';
327.\" auto-generated by docbook2man-spec from docbook-utils package
328_END_BANNER
329
330        my $manpage_date = $_[0]->parent->ext->{'date'} || $default_date;
331
332        output '.TH "';
333
334        # If the title is not mixed-case, convention says to
335        # uppercase the whole title.  (The canonical title is
336        # lowercase.)
337        if($manpage_title =~ /[A-Z]/) {
338                output fold_string($manpage_title);
339        } else {
340                output uc(fold_string($manpage_title));
341        }
342       
343        output  '" "', fold_string($manpage_sect), 
344                '" "', fold_string($manpage_date),
345                '" "', $manpage_misc, 
346                '" "', $manpage_manual, 
347                "\"\n";
348
349        $newline_last = 1;
350
351        # References to this RefEntry.
352        if(defined($_[0]->parent->attribute('ID')->value)) {
353                my $id = $_[0]->parent->attribute('ID')->value;
354
355                # Append XREFLABEL content to citations.
356                if(defined($_[0]->parent->attribute('XREFLABEL')->value)) {
357                        $citation = $_[0]->parent->attribute('XREFLABEL')->value .
358                                        ' [' . $citation . ']';
359                }
360
361                $Refs->put("refentry:$id", $citation);
362        }
363});
364
365sgml('<REFENTRYTITLE>', sub { 
366        if($_[0]->in('REFMETA')) { 
367                save_cdata();
368        } else { 
369                # Manpage citations are in bold.
370                bold_on();
371        }
372});
373sgml('</REFENTRYTITLE>', sub { 
374        if($_[0]->in('REFMETA')) {
375                $raw_cdata--;
376                $manpage_title = pop_output();
377        }
378        else { font_off(); }
379
380        if (defined($_[0]->attribute('ID')->value)) {
381                my $id = $_[0]->attribute('ID')->value;
382                $Refs->put("refentrytitle:$id", $manpage_title);
383        }
384});
385
386sgml('<MANVOLNUM>', sub { 
387        if($_[0]->in('REFMETA')) { 
388                save_cdata();   
389        } else {
390                # Manpage citations use ().
391                output '(';
392        }
393});
394sgml('</MANVOLNUM>', sub { 
395        if($_[0]->in('REFMETA')) {
396                $raw_cdata--;
397                $manpage_sect = pop_output();
398        }
399        else { output ')' }
400});
401
402sgml('<REFMISCINFO>', \&save_cdata);
403sgml('</REFMISCINFO>', sub { 
404        $raw_cdata--;
405        $manpage_misc = fold_string(pop_output());
406});
407
408
409# NAME section
410#man_sgml('<REFNAMEDIV>', "\n.SH NAME\n");
411man_sgml('<REFNAMEDIV>', sub {
412        my %text = { fr=>'NOM', es=>'NOMBRE', pl=>'NAZWA' };
413       
414        if(defined $text{lc($manpage_lang)})
415        {
416                man_output "\n.SH " . $text{lc($manpage_lang)} . "\n";
417        } elsif(defined $_[0]->attribute('LANG') and
418                defined $text{lc($_[0]->attribute('LANG')->value)})
419        {
420                man_output "\n.SH " . $text{lc($_[0]->attribute('LANG'))} . "\n";
421        } else {
422                man_output "\n.SH NAME\n";
423        }
424});
425
426sgml('<REFNAME>', \&save_cdata);
427sgml('</REFNAME>', sub { 
428        $raw_cdata--;
429        push(@manpage_names, pop_output());
430});
431
432sgml('<REFPURPOSE>', \&save_cdata);
433sgml('</REFPURPOSE>', sub { 
434        $raw_cdata--;
435        my $manpage_purpose = fold_string(pop_output());
436       
437        for(my $i = 0; $i < $#manpage_names; $i++) {
438                output fold_string($manpage_names[$i]), ', ';
439        }
440
441        output fold_string($manpage_names[$#manpage_names]);
442        output " \\- $manpage_purpose\n";
443
444        $newline_last = 1;
445
446        foreach(@manpage_names) {
447                # Don't link to itself
448                if($_ ne $manpage_title) {
449                        print LINKSFILE "$manpage_title.$manpage_sect   $_.$manpage_sect\n";
450                }
451        }
452});
453       
454man_sgml('<REFCLASS>', "\n.sp\n");
455
456#RefDescriptor
457
458
459########################################################################
460#
461# SYNOPSIS section and synopses
462#
463########################################################################
464
465#man_sgml('<REFSYNOPSISDIV>', "\n.SH SYNOPSIS\n");
466man_sgml('<REFSYNOPSISDIV>', sub {
467           if ($manpage_lang eq "pl") { man_output "\n.SH SK£ADNIA\n"; }
468           # waits for another languages
469           #elsif ($manpage_lang eq "xx") { man_output "\n.SH xxxxxxx\n"; }
470           else { man_output "\n.SH SYNOPSIS\n"; }
471});   
472
473man_sgml('</REFSYNOPSISDIV>', "\n");
474
475## FIXME! Must be made into block elements!!
476#sgml('<FUNCSYNOPSIS>', \&bold_on);
477#sgml('</FUNCSYNOPSIS>', \&font_off);
478#sgml('<CMDSYNOPSIS>', \&bold_on);
479#sgml('</CMDSYNOPSIS>', \&font_off);
480
481man_sgml('<FUNCSYNOPSIS>', sub {
482        man_output("\n.nf\n");
483        bold_on();
484});
485man_sgml('</FUNCSYNOPSIS>', sub {
486        man_output("\n.fi");
487        font_off();
488});
489
490man_sgml('<CMDSYNOPSIS>', "\n.sp\n");
491man_sgml('</CMDSYNOPSIS>', "\n");
492
493man_sgml('<FUNCPROTOTYPE>', "\n.sp\n");
494
495# Arguments to functions.  This is C convention.
496#man_sgml('<PARAMDEF>', '(');
497#man_sgml('</PARAMDEF>', ");\n");
498#man_sgml('<VOID>', "(void);\n");
499sub paramdef
500{
501        if($_[0]->parent->ext->{'inparams'}) {
502                output ', ';
503        } else {
504                output ' (';
505                $_[0]->parent->ext->{'inparams'} = 1;
506        }
507}
508man_sgml('<PARAMDEF>', \&paramdef);
509man_sgml('</FUNCPROTOTYPE>', ");\n");
510man_sgml('<VOID>', "(void");
511man_sgml('<VARARGS>', "(...");
512
513
514sub arg_start
515{
516        # my $choice = $_[0]->attribute('CHOICE')->value;
517
518        # The content model for CmdSynopsis doesn't include #PCDATA,
519        # so we won't see any of the whitespace in the source file,
520        # so we have to add it after each component.
521        man_output ' ';
522
523        if($_[0]->attribute('CHOICE')->value =~ /opt/i) {
524                man_output '[ ';
525        }
526        bold_on();
527}
528sub arg_end
529{
530        font_off();
531        if($_[0]->attribute('REP')->value =~ /^Repeat/i) {
532                italic_on();
533                man_output '...';
534                font_off();
535        }
536        if($_[0]->attribute('CHOICE')->value =~ /opt/i) {
537                man_output ' ] ';
538        }
539}
540
541sgml('<ARG>', \&arg_start);
542sgml('</ARG>', \&arg_end);
543sgml('<GROUP>', \&arg_start);
544sgml('</GROUP>', \&arg_end);
545
546sgml('<OPTION>', \&bold_on);
547sgml('</OPTION>', \&font_off);
548
549# FIXME: This is one _blank_ line.
550man_sgml('<SBR>', "\n\n");
551
552
553########################################################################
554#
555# General sections
556#
557########################################################################
558
559# The name of the section is handled by TITLE.  This just sets
560# up the roff markup.
561man_sgml('<REFSECT1>', sub { $separator = ''; man_output "\n.SH "});
562man_sgml('<REFSECT2>', sub { $separator = ''; man_output "\n.SS "});
563man_sgml('<REFSECT3>', sub { $separator = ''; man_output "\n.SS "});
564
565
566########################################################################
567#
568# Titles, metadata.
569#
570########################################################################
571
572sgml('<TITLE>', sub {
573        if($_[0]->in('REFERENCE') or $_[0]->in('BOOK')) {
574                $write_manpages = 1;
575        }
576        save_cdata();
577});
578sgml('</TITLE>', sub {
579        my ($element, $event) = @_;
580        my $title = fold_string(pop_output());
581        $raw_cdata--;
582       
583        if($element->in('REFERENCE') or $element->in('BOOK')) {
584                # We use TITLE of enclosing Reference or Book as manual name
585                $manpage_manual = $title;
586                $write_manpages = 0;
587        }
588        elsif(exists $element->parent->ext->{'title'}) {
589                # By far the easiest case.  Just fold the string as
590                # above, and then set the parent element's variable.
591                $_[0]->parent->ext->{'title'} = $title;
592        }
593        else {
594                # If the parent element's handlers are lazy,
595                # output the folded string for them :)
596                # We assume they want uppercase and a newline.
597                man_output '"', uc($title), "\"\n";
598        }
599
600        if (defined($element->attribute('ID')->value)) {
601                my $id = $_[0]->attribute('ID')->value;
602                $Refs->put("title:$id", $title);
603        }
604
605        my ($filename, $citation) =
606                FileInfo($manpage_title, $manpage_sect || $default_sect);
607        my $parentid = $element->parent->attribute('ID')->value;
608        if ($parentid and ($element->in('REFSECT1') or $element->in('REFSECT2') or $element->in('REFSECT3'))) {
609                $Refs->put("refsect:$parentid", "$citation");
610        }
611});
612
613sgml('<ATTRIBUTION>', sub { 
614        if($_[0]->in('BLOCKQUOTE')) {
615                push_output('string');
616        }
617});
618sgml('</ATTRIBUTION>', sub { 
619        if($_[0]->in('BLOCKQUOTE')) {
620                $_[0]->parent->ext->{'attribution'} = pop_output(); 
621        } else {
622                # For an Epigraph.
623                man_output "\n\n";
624        }
625});
626
627sgml('<DATE>', sub {
628      save_cdata();
629});
630sgml('</DATE>', sub {
631      $_[0]->parent->parent->ext->{'date'} = fold_string(pop_output());
632      $raw_cdata--;
633});
634
635sub ignore_content { push_output 'nul'; }
636sub restore_content { pop_output(); }
637
638sgml('<DOCINFO>', \&ignore_content);
639sgml('</DOCINFO>', \&restore_content);
640sgml('<REFSYNOPSISDIVINFO>', \&ignore_content);
641sgml('</REFSYNOPSISDIVINFO>', \&restore_content);
642sgml('<REFSECT1INFO>', \&ignore_content);
643sgml('</REFSECT1INFO>', \&restore_content);
644sgml('<REFSECT2INFO>', \&ignore_content);
645sgml('</REFSECT2INFO>', \&restore_content);
646sgml('<REFSECT3INFO>', \&ignore_content);
647sgml('</REFSECT3INFO>', \&restore_content);
648
649sgml('<INDEXTERM>', \&ignore_content);
650sgml('</INDEXTERM>', \&restore_content);
651
652sgml('<AUTHORBLURB>', \&ignore_content);
653sgml('</AUTHORBLURB>', \&restore_content);
654
655
656########################################################################
657#
658# Set bold on enclosed content
659#
660########################################################################
661
662sgml('<APPLICATION>', \&bold_on);
663sgml('</APPLICATION>', \&font_off);
664
665sgml('<CLASSNAME>', \&bold_on);         sgml('</CLASSNAME>', \&font_off);
666sgml('<STRUCTNAME>', \&bold_on);        sgml('</STRUCTNAME>', \&font_off);
667sgml('<STRUCTFIELD>', \&bold_on);       sgml('</STRUCTFIELD>', \&font_off);
668sgml('<SYMBOL>', \&bold_on);            sgml('</SYMBOL>', \&font_off);
669sgml('<TYPE>', \&bold_on);              sgml('</TYPE>', \&font_off);
670
671sgml('<ENVAR>', \&bold_on);     sgml('</ENVAR>', \&font_off);
672
673sgml('<FUNCTION>', \&bold_on);  sgml('</FUNCTION>', \&font_off);
674
675sgml('<EMPHASIS>', \&bold_on);  sgml('</EMPHASIS>', \&font_off);
676
677sgml('<ERRORNAME>', \&bold_on); sgml('</ERRORNAME>', \&font_off);
678# ERRORTYPE
679
680sgml('<COMMAND>', \&bold_on);   sgml('</COMMAND>', \&font_off);
681
682sgml('<GUIBUTTON>', \&bold_on); sgml('</GUIBUTTON>', \&font_off);
683sgml('<GUIICON>', \&bold_on);   sgml('</GUIICON>', \&font_off);
684# GUILABEL
685# GUIMENU
686# GUIMENUITEM
687# GUISUBMENU
688# MENUCHOICE
689
690sgml('<ACCEL>', \&bold_on);     sgml('</ACCEL>', \&font_off);
691# KEYCODE
692# SHORTCUT
693
694
695sgml('<KEYCOMBO>', sub {
696        $separator = 'none';
697        $_[0]->ext->{'separator'} = 'none';
698});
699sgml('</KEYCOMBO>', sub { $separator = $_[0]->parent->ext->{'separator'}; });
700
701sub _keycombo {
702        if($_[0]->in('KEYCOMBO')) {
703                if($separator eq 'none') { $separator = '' }
704                else { man_output "+"; }
705        }
706        bold_on();
707}
708sgml('<KEYCAP>', \&_keycombo);  sgml('</KEYCAP>', \&font_off);
709sgml('<KEYSYM>', \&_keycombo);  sgml('</KEYSYM>', \&font_off);
710sgml('<MOUSEBUTTON>', \&_keycombo);     sgml('</MOUSEBUTTON>', \&font_off);
711
712
713sgml('<USERINPUT>', \&bold_on); sgml('</USERINPUT>', \&font_off);
714
715sgml('<INTERFACEDEFINITION>', \&bold_on);
716sgml('</INTERFACEDEFINITION>', \&font_off);
717
718# May need to look at the CLASS
719sgml('<SYSTEMITEM>', \&bold_on);
720sgml('</SYSTEMITEM>', \&font_off);
721
722
723########################################################################
724#
725# Set italic on enclosed content
726#
727########################################################################
728
729sgml('<FIRSTTERM>', \&italic_on);       sgml('</FIRSTTERM>', \&font_off);
730
731sgml('<FILENAME>', \&italic_on);        sgml('</FILENAME>', \&font_off);
732sgml('<PARAMETER>', \&italic_on);       sgml('</PARAMETER>', \&font_off);
733sgml('<PROPERTY>', \&italic_on);        sgml('</PROPERTY>', \&font_off);
734
735sgml('<REPLACEABLE>', sub {
736        italic_on();
737        if($_[0]->in('TOKEN')) {
738                # When tokenizing, follow more 'intuitive' convention
739                output "<";
740        }
741});
742sgml('</REPLACEABLE>', sub {
743        if($_[0]->in('TOKEN')) {
744                output ">";
745        }
746        font_off();
747});
748
749sgml('<CITETITLE>', \&italic_on);       sgml('</CITETITLE>', \&font_off);
750sgml('<FOREIGNPHRASE>', \&italic_on);   sgml('</FOREIGNPHRASE>', \&font_off);
751
752sgml('<LINEANNOTATION>', \&italic_on);  sgml('</LINEANNOTATION>', \&font_off);
753
754
755########################################################################
756#
757# Other 'inline' elements
758#
759########################################################################
760
761man_sgml('<EMAIL>', '<');
762man_sgml('</EMAIL>', '>');
763man_sgml('<OPTIONAL>', '[');
764man_sgml('</OPTIONAL>', ']');
765
766man_sgml('</TRADEMARK>', "\\u\\s-2TM\\s+2\\d");
767
768man_sgml('<COMMENT>', "[Comment: ");
769man_sgml('</COMMENT>', "]");
770
771man_sgml('<QUOTE>', "``");
772man_sgml('</QUOTE>', "''");
773
774#man_sgml('<LITERAL>', '"');
775#man_sgml('</LITERAL>', '"');
776# There doesn't seem to be a good way to represent LITERAL in -man
777# ComputerOutput, SGMLTag, Markup are the same thing.
778
779# These create spaces between content in special elements
780# without PCDATA content.
781man_sgml('</HONORIFIC>', " ");
782man_sgml('</FIRSTNAME>', " ");
783man_sgml('</SURNAME>', " ");
784man_sgml('</LINEAGE>', " ");
785man_sgml('</OTHERNAME>', " ");
786
787man_sgml('<AFFILIATION>', "(");
788man_sgml('</AFFILIATION>', ") ");
789man_sgml('<CONTRIB>', "(");
790man_sgml('</CONTRIB>', ") ");
791
792man_sgml('</STREET>', " ");
793man_sgml('</POB>', " ");
794man_sgml('</POSTCODE>', " ");
795man_sgml('</CITY>', " ");
796man_sgml('</STATE>', " ");
797man_sgml('</COUNTRY>', " ");
798man_sgml('</PHONE>', " ");
799man_sgml('</FAX>', " ");
800man_sgml('</OTHERADDRESS>', " ");
801
802man_sgml('</ALT>', ": ");
803man_sgml('<GRAPHIC>', " [GRAPHIC] ");
804
805# No special presentation:
806
807# AUTHORINITIALS
808
809# ABBREV
810# ACTION
811# ACRONYM
812# CITATION
813# PHRASE
814# QUOTE
815# WORDASWORD
816
817# PROMPT
818# RETURNVALUE
819# TOKEN
820
821# DATABASE
822# HARDWARE
823# INTERFACE
824# MEDIALABEL
825
826
827########################################################################
828#
829# Paragraph and paragraph-like elements
830#
831########################################################################
832
833sub para_start {
834        if($separator eq '' or $separator eq 'full') {
835                $separator = '';
836                man_output "\n.PP\n";
837        } elsif($separator eq 'blank') { 
838                man_output "\n\n";
839        } elsif($separator eq 'none' ) {
840                $_[0]->parent->ext->{'separator'} = 'blank';
841                $separator = 'blank';
842        }
843}
844# Actually applies to a few other block elements as well
845sub para_end {
846        $separator = $_[0]->parent->ext->{'separator'};
847        man_output "\n";
848}
849
850sgml('<PARA>', \&para_start);
851sgml('</PARA>', \&para_end);
852sgml('<SIMPARA>', \&para_start);
853sgml('</SIMPARA>', \&para_end);
854
855# Nothing special, except maybe FIXME set nobreak.
856sgml('<INFORMALEXAMPLE>', \&para_start);
857sgml('</INFORMALEXAMPLE>', \&para_end);
858
859
860########################################################################
861#
862# Blocks using SS sections
863#
864########################################################################
865
866# FIXME: We need to consider the effects of SS
867# in a hanging tag :(
868
869# Complete with the optional-title dilemma (again).
870sgml('<ABSTRACT>', sub {
871        $_[0]->ext->{'title'} = 'ABSTRACT';
872        output "\n" unless $newline_last++;
873        push_output('string');
874});
875sgml('</ABSTRACT>', sub {
876        my $content = pop_output();
877       
878        # As ABSTRACT is never on the same level as RefSect1,
879        # this leaves us with only .SS in terms of -man macros.
880        output ".SS \"", uc($_[0]->ext->{'title'}), "\"\n";
881
882        output $content;
883        output "\n" unless $newline_last++;
884});
885
886
887
888# Ah, I needed a break.  Example always has a title.
889sgml('<EXAMPLE>', sub { $separator = ''; man_output "\n.SS "});
890sgml('</EXAMPLE>', \&para_end);
891
892# Same with sidebar.
893sgml('<SIDEBAR>', sub { $separator = ''; man_output "\n.SS "});
894sgml('</SIDEBAR>', \&para_end);
895
896sgml('<FORMALPARA>', sub { $separator = ''; man_output "\n.SS "});
897sgml('</FORMALPARA>', \&para_end);
898
899sgml('<FIGURE>', sub { $separator = ''; man_output "\n.SS "});
900sgml('</FIGURE>', \&para_end);
901
902
903
904# NO title.
905sgml('<HIGHLIGHTS>', sub { $separator = ''; man_output "\n.SS HIGHLIGHTS\n"});
906sgml('</HIGHLIGHTS>', \&para_end);
907
908
909########################################################################
910#
911# Indented 'Block' elements
912#
913########################################################################
914
915sub indent_block_start
916{
917        $separator = '';
918        man_output "\n.sp\n.RS\n";
919}
920sub indent_block_end
921{
922        $separator = $_[0]->parent->ext->{'separator'};
923        man_output "\n.RE\n.sp\n";
924}
925
926sgml('<ADDRESS>', sub {
927        &indent_block_start;
928        if($_[0]->attribute('FORMAT')->type eq 'NOTATION'
929           and $_[0]->attribute('FORMAT')->value->name eq 'LINESPECIFIC') {
930                &verbatim_start;
931        }
932});
933sgml('</ADDRESS>', sub {
934        if($_[0]->attribute('FORMAT')->type eq 'NOTATION'
935           and $_[0]->attribute('FORMAT')->value->name eq 'LINESPECIFIC') {
936                &verbatim_end;
937        }
938        &indent_block_end;
939});
940       
941# This element is almost like an admonition (below),
942# only the default title is blank :)
943
944sgml('<BLOCKQUOTE>', sub { 
945        $_[0]->ext->{'title'} = ''; 
946        &indent_block_start;
947        push_output('string');
948});
949sgml('</BLOCKQUOTE>', sub {
950        my $content = pop_output();
951
952        if($_[0]->ext->{'title'}) {
953                output ".B \"", $_[0]->ext->{'title'}, ":\"\n";
954        }
955       
956        output $content;
957
958        if($_[0]->ext->{'attribution'}) {
959                man_output "\n\n                -- ",
960                                $_[0]->ext->{'attribution'}, "\n";
961        }
962       
963        &indent_block_end;
964});
965
966# Set off admonitions from the rest of the text by indenting.
967# FIXME: Need to check if this works inside paragraphs, not enclosing them.
968sub admonition_end {
969        my $content = pop_output();
970
971        # When the admonition is only one paragraph,
972        # it looks nicer if the title was inline.
973        my $num_para;
974        while ($content =~ /^\.PP/gm) { $num_para++ }
975        if($num_para==1) {
976                $content =~ s/^\.PP\n//;
977        }
978       
979        output ".B \"" . $_[0]->ext->{'title'} . ":\"\n";
980        output $content;
981       
982        &indent_block_end;
983}
984
985sgml('<NOTE>', sub {
986        # We can't see right now whether or not there is a TITLE
987        # element, so we have to save the output now and add it back
988        # at the end of this admonition.
989        $_[0]->ext->{'title'} = 'Note';
990       
991        &indent_block_start;
992       
993        push_output('string');
994});
995sgml('</NOTE>', \&admonition_end);
996
997# Same as above.
998sgml('<WARNING>', sub { 
999        $_[0]->ext->{'title'} = 'Warning'; 
1000        &indent_block_start;
1001        push_output('string');
1002});
1003sgml('</WARNING>', \&admonition_end);
1004
1005sgml('<TIP>', sub {
1006        $_[0]->ext->{'title'} = 'Tip';
1007        &indent_block_start;
1008        push_output('string');
1009});
1010sgml('</TIP>', \&admonition_end);
1011sgml('<CAUTION>', sub {
1012        $_[0]->ext->{'title'} = 'Caution';
1013        &indent_block_start;
1014        push_output('string');
1015});
1016sgml('</CAUTION>', \&admonition_end);
1017
1018sgml('<IMPORTANT>', sub {
1019        $_[0]->ext->{'title'} = 'Important';
1020        &indent_block_start;
1021        push_output('string');
1022});
1023sgml('</IMPORTANT>', \&admonition_end);
1024
1025
1026########################################################################
1027#
1028# Verbatim displays.
1029#
1030########################################################################
1031
1032sub verbatim_start {
1033        $separator = '';
1034        man_output "\n.sp\n";
1035        man_output "\n.nf\n" unless $nocollapse_whitespace++;
1036}
1037
1038sub verbatim_end {
1039        man_output "\n.sp\n";
1040        man_output "\n.fi\n" unless --$nocollapse_whitespace;
1041        $separator = $_[0]->parent->ext->{'separator'};
1042}
1043
1044sgml('<PROGRAMLISTING>', \&verbatim_start); 
1045sgml('</PROGRAMLISTING>', \&verbatim_end);
1046
1047sgml('<SCREEN>', \&verbatim_start); 
1048sgml('</SCREEN>', \&verbatim_end);
1049
1050sgml('<LITERALLAYOUT>', \&verbatim_start); 
1051sgml('</LITERALLAYOUT>', \&verbatim_end);
1052
1053sgml('<SYNOPSIS>', sub {
1054        my $format = $_[0]->attribute('FORMAT');
1055
1056        if($format->type eq 'NOTATION'
1057           and $format->value->name eq 'LINESPECIFIC')
1058        {
1059                &verbatim_start;
1060        } else {
1061                $separator = '';
1062                man_output "\n.sp\n";
1063        }
1064});
1065
1066sgml('</SYNOPSIS>', sub {
1067        my $format = $_[0]->attribute('FORMAT');
1068       
1069        if($format->type eq 'NOTATION'
1070           and $format->value->name eq 'LINESPECIFIC')
1071        {
1072                &verbatim_end;
1073        } else {
1074                man_output "\n";
1075                $_[0]->parent->ext->{'separator'} = 'full';
1076                $separator = 'full';
1077        }
1078});
1079
1080
1081########################################################################
1082#
1083# Lists
1084#
1085########################################################################
1086
1087# Indent nested lists.
1088sub list_start {
1089        man_output "\n.RS\n" if $list_nestlevel++;
1090}
1091sub list_end {
1092        man_output "\n.RE\n" if --$list_nestlevel;
1093        $_[0]->parent->ext->{'separator'} = 'full';
1094        $separator = 'full';
1095}
1096
1097sgml('<VARIABLELIST>', \&list_start);
1098sgml('</VARIABLELIST>', \&list_end);
1099sgml('<ITEMIZEDLIST>', \&list_start);
1100sgml('</ITEMIZEDLIST>', \&list_end);
1101sgml('<ORDEREDLIST>', sub { 
1102        &list_start;
1103        $_[0]->ext->{'count'} = 1;
1104});
1105sgml('</ORDEREDLIST>', \&list_end);
1106               
1107# Output content on one line, bolded.
1108sgml('<TERM>', sub { 
1109        man_output "\n.TP\n";
1110        bold_on();
1111        push_output('string');
1112});
1113sgml('</TERM>', sub { 
1114        my $term = StripString(pop_output());
1115        $term =~ tr/\n/ /;
1116        output $term;
1117        font_off();
1118        output "\n";
1119        $newline_last = 1;
1120});
1121       
1122sgml('<LISTITEM>', sub {
1123        # A bulleted list.
1124        if($_[0]->in('ITEMIZEDLIST')) {
1125                man_output "\n.TP 0.2i\n\\(bu\n";
1126        }
1127
1128        # Need numbers.
1129        # Assume Arabic numeration for now.
1130        elsif($_[0]->in('ORDEREDLIST')) {
1131                man_output "\n.IP ", $_[0]->parent->ext->{'count'}++, ". \n";
1132        }
1133       
1134        $_[0]->ext->{'separator'} = 'none';
1135        $separator = 'none';
1136});
1137
1138sgml('<SIMPLELIST>', sub {
1139        $_[0]->ext->{'first_member'} = 1;
1140});
1141sgml('<MEMBER>', sub {
1142        my $parent = $_[0]->parent;
1143       
1144        if($parent->attribute('TYPE')->value =~ /Inline/i) {
1145                if($parent->ext->{'first_member'}) {
1146                        # If this is the first member don't put any commas
1147                        $parent->ext->{'first_member'} = 0;
1148                } else {
1149                        man_output ", ";
1150                }
1151
1152        # We don't really have Horiz rendering, so it's the same
1153        # as Vert.
1154        } else {
1155                man_output "\n\n";
1156        }
1157});
1158
1159# We implement Procedures as indent and lists
1160
1161sgml('<PROCEDURE>', sub {
1162        $_[0]->ext->{'count'} = 1;
1163        &indent_block_start;
1164});
1165sgml('</PROCEDURE>', sub {
1166        &indent_block_end;
1167        $_[0]->parent->ext->{'separator'} = 'full';
1168        $separator = 'full';
1169});
1170
1171sgml('<STEP>', sub {
1172        man_output "\n.IP ", $_[0]->parent->ext->{'count'}++, ". \n";
1173        $_[0]->ext->{'separator'} = 'none';
1174        $separator = 'none';
1175});
1176
1177
1178########################################################################
1179#
1180# Linkage, cross references
1181#
1182########################################################################
1183
1184# Print the URL
1185sgml('</ULINK>', sub {
1186        man_output ' <URL:', $_[0]->attribute('URL')->value, '>';
1187});
1188
1189# If cross reference target is a RefEntry,
1190# output CiteRefEntry-style references.
1191sgml('<XREF>', sub {
1192        my $id = $_[0]->attribute('LINKEND')->value;
1193
1194        my $manref = $Refs->get("refentry:$id") || $Refs->get("refsect:$id");
1195        if(!defined $manref) {
1196                $blank_xrefs++ if $write_manpages;
1197                man_output "[XRef to $id]";
1198                return;
1199        }
1200
1201        # Limited ENDTERM support.
1202        if(defined $_[0]->attribute('ENDTERM')->value) {
1203                my $endterm = $_[0]->attribute('ENDTERM')->value;
1204                my $content = $Refs->get("title:$endterm") ||
1205                                $Refs->get("refentrytitle:$endterm");
1206                man_output $content, ' [';
1207        }
1208
1209        # This also displays the XREFLABEL (as bold)...
1210        # It's not worth the bother to fix it though, there
1211        # are better tools for this.
1212        my ($title, $sect) = ($manref =~ /(.*)(\(.*\))/);
1213        bold_on();
1214        man_output $title;
1215        font_off();
1216        man_output $sect;
1217
1218        if(defined $_[0]->attribute('ENDTERM')->value) {
1219                man_output ']';
1220        }
1221});
1222
1223# Anchor
1224
1225########################################################################
1226#
1227# SDATA
1228#
1229########################################################################
1230
1231man_sgml('|[lt    ]|', '<');
1232man_sgml('|[equals]|', '=');
1233man_sgml('|[gt    ]|', '>');
1234man_sgml('|[plus  ]|', '\(pl');
1235man_sgml('|[dollar]|', '$');
1236man_sgml('|[num   ]|', '#');
1237man_sgml('|[percnt]|', '%');
1238man_sgml('|[amp   ]|', '&');
1239man_sgml('|[commat]|', '@');
1240man_sgml('|[lsqb  ]|', '[');
1241man_sgml('|[bsol  ]|', '\e');
1242man_sgml('|[rsqb  ]|', ']');
1243man_sgml('|[lcub  ]|', '{');
1244man_sgml('|[verbar]|', '\(or');
1245man_sgml('|[rcub  ]|', '}');
1246man_sgml('|[excl  ]|', '!');
1247man_sgml('|[quot  ]|', '"');
1248man_sgml('|[apos  ]|', '\\&\'');
1249man_sgml('|[lpar  ]|', '(');
1250man_sgml('|[rpar  ]|', ')');
1251man_sgml('|[comma ]|', ',');
1252man_sgml('|[lowbar]|', '_');
1253man_sgml('|[period]|', '.');
1254man_sgml('|[sol   ]|', '/');
1255man_sgml('|[colon ]|', ':');
1256man_sgml('|[semi  ]|', ';');
1257man_sgml('|[quest ]|', '?');
1258man_sgml('|[grave ]|', '`');
1259man_sgml('|[tilde ]|', '~');
1260man_sgml('|[half  ]|', '\(12');
1261man_sgml('|[frac12]|', '\(12');
1262man_sgml('|[frac14]|', '\(14');
1263man_sgml('|[frac34]|', '\(34');
1264man_sgml('|[frac18]|', '1/8');
1265man_sgml('|[frac38]|', '3/8');
1266man_sgml('|[frac58]|', '5/8');
1267man_sgml('|[frac78]|', '7/8');
1268man_sgml('|[sup1  ]|', '\u1\l');
1269man_sgml('|[sup2  ]|', '\u2\l');
1270man_sgml('|[sup3  ]|', '\u3\l');
1271man_sgml('|[plusmn]|', '\(+-');
1272man_sgml('|[divide]|', '\(di');
1273man_sgml('|[times ]|', '\(ti');
1274man_sgml('|[pound ]|', '#');
1275man_sgml('|[cent  ]|', '\(ct');
1276man_sgml('|[yen   ]|', 'yen');
1277man_sgml('|[ast   ]|', '*');
1278man_sgml('|[horbar]|', '_');
1279man_sgml('|[micro ]|', '\(*m');
1280man_sgml('|[ohm   ]|', '\(*W');
1281man_sgml('|[deg   ]|', '\(de');
1282man_sgml('|[sect  ]|', '\(sc');
1283man_sgml('|[larr  ]|', '\(<-');
1284man_sgml('|[rarr  ]|', '\(->');
1285man_sgml('|[uarr  ]|', '\(ua');
1286man_sgml('|[darr  ]|', '\(da');
1287man_sgml('|[copy  ]|', '\(co');
1288man_sgml('|[reg   ]|', '\(rg');
1289man_sgml('|[trade ]|', '\(tm');
1290man_sgml('|[brvbar]|', '|');
1291man_sgml('|[not   ]|', '\(no');
1292man_sgml('|[hyphen]|', '\-');
1293man_sgml('|[laquo ]|', '<<');
1294man_sgml('|[raquo ]|', '>>');
1295man_sgml('|[lsquo ]|', '`');
1296man_sgml('|[rsquo ]|', '\&\'');
1297man_sgml('|[ldquo ]|', '"');
1298man_sgml('|[rdquo ]|', '"');
1299man_sgml('|[nbsp  ]|', '\ ');
1300man_sgml('|[shy   ]|', '\%');
1301man_sgml('|[emsp  ]|', '\ \ ');
1302man_sgml('|[ensp  ]|', '\ ');
1303man_sgml('|[emsp3 ]|', '\ ');
1304man_sgml('|[emsp4 ]|', '\ ');
1305man_sgml('|[numsp ]|', '\0');
1306man_sgml('|[puncsp]|', '\|');
1307man_sgml('|[thinsp]|', '\!');
1308man_sgml('|[hairsp]|', '\\^');
1309man_sgml('|[mdash ]|', '\(em');
1310man_sgml('|[ndash ]|', '-');
1311man_sgml('|[dash  ]|', '-');
1312man_sgml('|[blank ]|', '\ ');
1313man_sgml('|[hellip]|', '\&...');
1314man_sgml('|[nldr  ]|', '\&..');
1315man_sgml('|[frac13]|', '1/3');
1316man_sgml('|[frac23]|', '2/3');
1317man_sgml('|[frac15]|', '1/5');
1318man_sgml('|[frac25]|', '2/5');
1319man_sgml('|[frac35]|', '3/5');
1320man_sgml('|[frac45]|', '4/5');
1321man_sgml('|[frac16]|', '1/6');
1322man_sgml('|[frac56]|', '5/6');
1323man_sgml('|[cir   ]|', '\(ci');
1324man_sgml('|[squ   ]|', '\(sq');
1325man_sgml('|[star  ]|', '\(**');
1326man_sgml('|[bull  ]|', '\(bu');
1327man_sgml('|[dagger]|', '\(dg');
1328man_sgml('|[Dagger]|', '\(dd');
1329man_sgml('|[caret ]|', '\^');
1330man_sgml('|[lsquor]|', '`');
1331man_sgml('|[ldquor]|', '``');
1332man_sgml('|[fflig ]|', '\(ff');
1333man_sgml('|[filig ]|', '\(fi');
1334man_sgml('|[ffilig]|', '\(Fi');
1335man_sgml('|[ffllig]|', '\(Fl');
1336man_sgml('|[fllig ]|', '\(fl');
1337man_sgml('|[rdquor]|', '\&\'\'');
1338man_sgml('|[rsquor]|', '\&\'');
1339man_sgml('|[vellip]|', '\&...');
1340man_sgml('|[aacute]|', '\(a\'');
1341man_sgml('|[Aacute]|', '\(A\'');
1342man_sgml('|[acirc ]|', '\(a^');
1343man_sgml('|[Acirc ]|', '\(A^');
1344man_sgml('|[agrave]|', '\(a`');
1345man_sgml('|[Agrave]|', '\(A`');
1346man_sgml('|[auml  ]|', '\(a:');
1347man_sgml('|[aelig ]|', '\(ae');
1348man_sgml('|[AElig ]|', '\(AE');
1349man_sgml('|[eacute]|', '\(e\'');
1350man_sgml('|[Eacute]|', '\(E\'');
1351man_sgml('|[egrave]|', '\(e`');
1352man_sgml('|[Egrave]|', '\(E`');
1353man_sgml('|[iacute]|', '\(i\'');
1354man_sgml('|[Iacute]|', '\(I\'');
1355man_sgml('|[igrave]|', '\(i`');
1356man_sgml('|[Igrave]|', '\(I`');
1357man_sgml('|[ntilde]|', '\(n~');
1358man_sgml('|[Ntilde]|', '\(N~');
1359man_sgml('|[oacute]|', '\(o\'');
1360man_sgml('|[Oacute]|', '\(O\'');
1361man_sgml('|[ograve]|', '\(o`');
1362man_sgml('|[Ograve]|', '\(O`');
1363man_sgml('|[oslash]|', '\(o/');
1364man_sgml('|[Oslash]|', '\(O/');
1365man_sgml('|[szlig ]|', '\(ss');
1366man_sgml('|[thorn ]|', '\(th');
1367man_sgml('|[uacute]|', '\(u\'');
1368man_sgml('|[Uacute]|', '\(U\'');
1369man_sgml('|[ugrave]|', '\(u`');
1370man_sgml('|[Ugrave]|', '\(U`');
1371man_sgml('|[aogon ]|', '\(ao');
1372man_sgml('|[agr   ]|', '\(*a');
1373man_sgml('|[Agr   ]|', '\(*A');
1374man_sgml('|[bgr   ]|', '\(*b');
1375man_sgml('|[Bgr   ]|', '\(*B');
1376man_sgml('|[ggr   ]|', '\(*g');
1377man_sgml('|[Ggr   ]|', '\(*G');
1378man_sgml('|[dgr   ]|', '\(*d');
1379man_sgml('|[Dgr   ]|', '\(*D');
1380man_sgml('|[egr   ]|', '\(*e');
1381man_sgml('|[Egr   ]|', '\(*E');
1382man_sgml('|[zgr   ]|', '\(*z');
1383man_sgml('|[Zgr   ]|', '\(*Z');
1384man_sgml('|[eegr  ]|', '\(*y');
1385man_sgml('|[EEgr  ]|', '\(*Y');
1386man_sgml('|[thgr  ]|', '\(*h');
1387man_sgml('|[THgr  ]|', '\(*H');
1388man_sgml('|[igr   ]|', '\(*i');
1389man_sgml('|[Igr   ]|', '\(*I');
1390man_sgml('|[kgr   ]|', '\(*k');
1391man_sgml('|[Kgr   ]|', '\(*K');
1392man_sgml('|[lgr   ]|', '\(*l');
1393man_sgml('|[Lgr   ]|', '\(*L');
1394man_sgml('|[mgr   ]|', '\(*m');
1395man_sgml('|[Mgr   ]|', '\(*M');
1396man_sgml('|[ngr   ]|', '\(*n');
1397man_sgml('|[Ngr   ]|', '\(*N');
1398man_sgml('|[xgr   ]|', '\(*c');
1399man_sgml('|[Xgr   ]|', '\(*C');
1400man_sgml('|[ogr   ]|', '\(*o');
1401man_sgml('|[Ogr   ]|', '\(*O');
1402man_sgml('|[pgr   ]|', '\(*p');
1403man_sgml('|[Pgr   ]|', '\(*P');
1404man_sgml('|[rgr   ]|', '\(*r');
1405man_sgml('|[Rgr   ]|', '\(*R');
1406man_sgml('|[sgr   ]|', '\(*s');
1407man_sgml('|[Sgr   ]|', '\(*S');
1408man_sgml('|[sfgr  ]|', '\(ts');
1409man_sgml('|[tgr   ]|', '\(*t');
1410man_sgml('|[Tgr   ]|', '\(*T');
1411man_sgml('|[ugr   ]|', '\(*u');
1412man_sgml('|[Ugr   ]|', '\(*U');
1413man_sgml('|[phgr  ]|', '\(*f');
1414man_sgml('|[PHgr  ]|', '\(*F');
1415man_sgml('|[khgr  ]|', '\(*x');
1416man_sgml('|[KHgr  ]|', '\(*X');
1417man_sgml('|[psgr  ]|', '\(*q');
1418man_sgml('|[PSgr  ]|', '\(*Q');
1419man_sgml('|[ohgr  ]|', '\(*w');
1420man_sgml('|[OHgr  ]|', '\(*W');
1421man_sgml('|[alpha ]|', '\(*a');
1422man_sgml('|[beta  ]|', '\(*b');
1423man_sgml('|[gamma ]|', '\(*g');
1424man_sgml('|[Gamma ]|', '\(*G');
1425man_sgml('|[delta ]|', '\(*d');
1426man_sgml('|[Delta ]|', '\(*D');
1427man_sgml('|[epsi  ]|', '\(*e');
1428man_sgml('|[epsis ]|', '\(*e');
1429man_sgml('|[zeta  ]|', '\(*z');
1430man_sgml('|[eta   ]|', '\(*y');
1431man_sgml('|[thetas]|', '\(*h');
1432man_sgml('|[Theta ]|', '\(*H');
1433man_sgml('|[iota  ]|', '\(*i');
1434man_sgml('|[kappa ]|', '\(*k');
1435man_sgml('|[lambda]|', '\(*l');
1436man_sgml('|[Lambda]|', '\(*L');
1437man_sgml('|[mu    ]|', '\(*m');
1438man_sgml('|[nu    ]|', '\(*n');
1439man_sgml('|[xi    ]|', '\(*c');
1440man_sgml('|[Xi    ]|', '\(*C');
1441man_sgml('|[pi    ]|', '\(*p');
1442man_sgml('|[Pi    ]|', '\(*P');
1443man_sgml('|[rho   ]|', '\(*r');
1444man_sgml('|[sigma ]|', '\(*s');
1445man_sgml('|[Sigma ]|', '\(*S');
1446man_sgml('|[tau   ]|', '\(*t');
1447man_sgml('|[upsi  ]|', '\(*u');
1448man_sgml('|[Upsi  ]|', '\(*U');
1449man_sgml('|[phis  ]|', '\(*f');
1450man_sgml('|[Phi   ]|', '\(*F');
1451man_sgml('|[chi   ]|', '\(*x');
1452man_sgml('|[psi   ]|', '\(*q');
1453man_sgml('|[Psi   ]|', '\(*X');
1454man_sgml('|[omega ]|', '\(*w');
1455man_sgml('|[Omega ]|', '\(*W');
1456man_sgml('|[ap    ]|', '\(ap');
1457man_sgml('|[equiv ]|', '\(==');
1458man_sgml('|[ge    ]|', '\(>=');
1459man_sgml('|[infin ]|', '\(if');
1460man_sgml('|[isin  ]|', '\(sb');
1461man_sgml('|[le    ]|', '\(<=');
1462man_sgml('|[minus ]|', '\(mi');
1463man_sgml('|[ne    ]|', '\(!=');
1464man_sgml('|[prop  ]|', '\(pt');
1465man_sgml('|[square]|', '\(sq');
1466man_sgml('|[sub   ]|', '\(sb');
1467man_sgml('|[sube  ]|', '\(ib');
1468man_sgml('|[sup   ]|', '\(sp');
1469man_sgml('|[supe  ]|', '\(ip');
1470man_sgml('|[acute ]|', '\&\'');
1471man_sgml('|[breve ]|', '\(be');
1472man_sgml('|[caron ]|', '\(hc');
1473man_sgml('|[cedil ]|', '\(cd');
1474man_sgml('|[dot   ]|', '\(dt');
1475man_sgml('|[macr  ]|', '\(ma');
1476man_sgml('|[ogon  ]|', '\(og');
1477man_sgml('|[ring  ]|', '\(ri');
1478man_sgml('|[uml   ]|', '\(..');
1479
1480sgml('sdata',sub {
1481        my ($element, $event) = @_;
1482        my ($file, $line) = ($event->file, $event->line);
1483        man_output "|[", $_[0], "]|";
1484        warn "Warning: unrecognized SDATA '$_[0]'"
1485             . ($file && $line ? " in $file on line $line" : "")
1486             . ": please add definition to docbook2man-spec.pl\n";
1487});
1488
1489#
1490# Default handlers (uncomment these if needed).  Right now, these are set
1491# up to gag on any unrecognised elements, sdata, processing-instructions,
1492# or entities.
1493#
1494# sgml('start_element',sub { die "Unknown element: " . $_[0]->name; });
1495# sgml('end_element','');
1496
1497# This is for weeding out and escaping certain characters.
1498# This looks like it's inefficient since it's done on every line, but
1499# in reality, SGMLSpm and sgmlspl parsing ESIS takes _much_ longer.
1500
1501sgml('cdata', sub
1502{ 
1503        if(!$write_manpages) { return; }
1504        elsif($raw_cdata) { output $_[0]; return; }
1505
1506        if($separator eq 'full') {
1507                output "\n" unless $newline_last++;
1508                output ".PP\n";
1509                $separator = '';
1510        }
1511       
1512        # Escape backslashes
1513        $_[0] =~ s/\\/\\\\/g;
1514
1515  # Escape dots and single quotes in column 1
1516        $_[0] =~ s/^[ \t]*\./\\\&\./;
1517        $_[0] =~ s/^[ \t]*\'/\\\&\'/;
1518
1519
1520        # In non-'pre'-type elements:
1521        if(!$nocollapse_whitespace) {
1522                # Change tabs to spaces
1523                $_[0] =~ tr/\t / /s;
1524
1525                # Do not allow indents at beginning of line
1526                # groff chokes on that.
1527                if($newline_last) { 
1528                        $_[0] =~ s/^ //;
1529
1530                        # If the line is all blank, don't do anything.
1531                        if($_[0] eq '') { return; }
1532                       
1533                        $_[0] =~ s/^\./\\\&\./;
1534       
1535                        # Argh... roff doesn't like ' for some unknown reason
1536                        $_[0] =~ s/^\'/\\\&\'/;
1537                }
1538        }
1539
1540        $newline_last = 0;
1541
1542        output $_[0];
1543});
1544
1545
1546# When in whitespace-collapsing mode, we disallow consecutive newlines.
1547
1548sgml('re', sub
1549{
1550        if($nocollapse_whitespace || !$newline_last) {
1551                output "\n";
1552        }
1553
1554        $newline_last = 1;
1555});
1556
1557sgml('pi', sub {});
1558sgml('entity',sub { die "Unknown external entity: " . $_[0]->name; });
1559sgml('start_subdoc',sub { die "Unknown subdoc entity: " . $_[0]->name; });
1560sgml('end_subdoc',sub{});
1561sgml('conforming',sub{});
1562
15631;
1564