man-page-conversion-20051208
[openafs.git] / doc / man-pages / generate-pod
1 #!/usr/bin/perl -w
2 #
3 # Convert the HTML pages of the Administrator's Reference into POD man pages.
4 # This script was written by Chas Williams and Russ Allbery, based on work by
5 # Alf Wachsmann and Elizabeth Cassell.  It just does a first pass; it's
6 # expected that the results will require further hand-editing.
7
8 use strict;
9 use HTML::Parser ();
10
11 my @ignore_tags = qw(meta head comment html body);
12 my @ignore_elements = qw(script style);
13
14 my %INLINES = ('b'    => 'B<',
15                '/b'   => '>',
16                'i'    => 'I<',
17                '/i'   => '>',
18                'var'  => 'I<',
19                '/var' => '>',
20                'tt'   => 'C<',
21                '/tt'  => '>',
22                'a'    => 'L<',
23                '/a'   => '(1)>',
24                'sup'  => '',
25                '/sup' => '');
26
27 my %CDATA = ('dd'     => 1,
28              'dt'     => 1,
29              'h2'     => 1,
30              'a'      => 1,
31              'li'     => 1,
32              'p'      => 1,
33              'pre'    => 1,
34              'strong' => 1);
35
36 # Global state of the conversion.
37 my $command = "";
38 my $output = 0;
39 my $emit = 0;
40 my $pre = 0;
41 my $buffer = "";
42 my $inpara = 0;
43 my $lasttag = "";
44 my $open = "";
45 my $cdata = "";
46 my $result = "";
47
48 # Output some data.  Accumulate this into $results so that we can do some
49 # post-filtering at the end.
50 sub output {
51     my ($format, @args) = @_;
52     $result .= sprintf($format, @args);
53 }
54
55 # Handle a single element.
56 sub element {
57     if ($output) {
58         $buffer =~ s/^\s+\n/\n/m;
59         $buffer =~ s/\n+$/\n/g;
60
61         if ($lasttag eq "h2") {
62             $command = $buffer;
63             $command =~ s/^L<//;
64             $command =~ s/\(1\)>$//;
65         } elsif ($lasttag eq "strong") {
66             if ($buffer eq 'Cautions') {
67                 $buffer = 'CAVEATS';
68             } elsif ($buffer eq 'Related Information') {
69                 $buffer = 'SEE ALSO';
70             } else {
71                 $buffer = uc $buffer;
72             }
73             if ($buffer eq 'PURPOSE') {
74                 output "=head1 NAME\n\n%s - ", $command;
75             } else {
76                 output "=head1 %s\n\n", $buffer;
77             }
78         } elsif ($lasttag eq "h5") {
79             output "=head2 %s\n\n", $buffer;
80         } elsif ($lasttag eq "h6") {
81             output "=head3 %s\n\n", $buffer;
82         } elsif ($lasttag eq "p") {
83             $buffer =~ s/\n+$//g;
84             output "%s\n\n", $buffer if $buffer ne "";
85         } elsif ($lasttag eq "pre") {
86             $buffer =~ s/\n+$//;
87             output "%s\n\n", $buffer if $buffer ne "";
88         } elsif ($lasttag eq "ul" || $lasttag eq "dl") {
89             output "=over 4\n\n";
90         } elsif ($lasttag eq "li") {
91             output "=item *\n\n%s\n\n", $buffer;
92         } elsif ($lasttag eq "dt") {
93             output "=item %s\n\n", $buffer;
94         } elsif ($lasttag eq "dd") {
95             output "%s\n", $buffer;
96         } elsif ($lasttag eq "/ul" || $lasttag eq "/dl") {
97             output "=back\n\n";
98         } else {
99             if ($buffer ne "") {
100                 printf ">>>%s:%s<<<", $lasttag, $buffer;
101             }
102         }
103     }
104     $buffer = "";
105 }
106
107 # Handle a single tag.
108 sub tag {
109     my $self = shift;
110     local $_ = shift;
111     my $tag = shift;
112     my $attr = shift;
113
114     $output = 1 if ($tag eq "h2");
115     $output = 0 if ($tag eq "hr");
116
117     if (defined $INLINES{$tag}) {
118         if (defined $open && $open eq $tag) {
119             printf STDERR "duplicate tag <%s>\n", $tag;
120             return;
121         }
122         if ($tag =~ /^\//) {
123             undef $open;
124         } else {
125             $open = $tag;
126         }
127
128         &text(sprintf "%s", $INLINES{$tag});
129         return;
130     }
131
132     $cdata = 0;
133     $cdata = 1 if defined $CDATA{$tag};
134
135     &element;
136     $lasttag = $tag;
137 }
138
139 # Do text conversion, mostly undoing SGML escapes.
140 sub text {
141     local $_ = shift;
142
143     if ($cdata) {
144         s/&amp;/&/g;
145         s/&nbsp;/ /g;
146         s/&gt;/>/g;
147         s/&lt;/</g;
148
149         s/\n$//g if defined $open;      # in inline seq, remove \n
150         s/L<(\S+) (\S+\(1\))>/L<${1}_${2}>/g;
151         $buffer = $buffer . $_;
152     }
153 }
154
155 my $file = shift @ARGV;
156
157 my $p = HTML::Parser->new(api_version     => 3,
158                           start_h         => [\&tag, "self, text, tag, attr"],
159                           end_h           => [\&tag, "self, text, tag, attr"],
160                           process_h       => ["", ""],
161                           comment_h       => ["", ""],
162                           declaration_h   => ["", ""],
163                           default_h       => [\&text, "text"],
164
165                           ignore_tags     => \@ignore_tags,
166                           ignore_elements => \@ignore_elements,
167                           unbroken_text   => 1);
168
169 $p->parse_file($file) || die "Can't open file: $!\n";
170
171 # Fix up a few last things.
172 $result =~ s/L<(\S+) (\S+\(1\))>/L<${1}_${2}>/g;
173 $result =~ s/^(L<\S+>)\n\n(?=L<)/$1,\n/mg;
174 $result =~ s/^(\S+[^\n]+)\n +/$1\n/mg;
175 $result =~ s/^(\s+.*)B<([^>]+)>/$1$2/mg;
176
177 # Append a stock copyright statement.
178 $result .= <<'EOC';
179 =head1 COPYRIGHT
180
181 IBM Corporation 2000. <http://www.ibm.com/> All Rights Reserved.
182
183 This documentation is covered by the IBM Public License Version 1.0.  It was
184 converted from HTML to POD by software written by Chas Williams and Russ
185 Allbery, based on work by Alf Wachsmann and Elizabeth Cassell.
186 EOC
187
188 # Output the results.
189 print $result;