3 # Generate a man page from sections of a Texinfo manual.
5 # Copyright 2004 The Free Software Foundation,
7 # & Ximbiot <http://ximbiot.com>
9 # This program is free software; you can redistribute it and/or modify
10 # it under the terms of the GNU General Public License as published by
11 # the Free Software Foundation; either version 2, or (at your option)
14 # This program is distributed in the hope that it will be useful,
15 # but WITHOUT ANY WARRANTY; without even the implied warranty of
16 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 # GNU General Public License for more details.
19 # You should have received a copy of the GNU General Public License
20 # along with this program; if not, write to the Free Software Foundation,
21 # Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
25 # Need Perl 5.005 or greater for re 'eval'.
37 my $texi_num = 0; # Keep track of how many texinfo files have been encountered.
38 my @parent; # This needs to be global to be used inside of a regex later.
47 my ($keyword, $file) = @_;
50 if $keyword =~ /^(|r|t)$/;
52 if $keyword =~ /^(strong|sc|code|file|samp)$/;
54 if $keyword =~ /^(emph|var|dfn)$/;
55 die "no handler for keyword \`$keyword', found at line $. of file \`$file'\n";
60 # Return replacement for \@$keyword{$content}.
63 my ($file, $parent, $keyword, $content) = @_;
65 return "see node \`$content\\(aq in the CVS manual"
66 if $keyword =~ /^(p?x)?ref$/;
67 return "\\fP\\fP$content"
68 if $keyword =~ /^splitrcskeyword$/;
70 my $endmode = keyword_mode $parent;
71 my $startmode = keyword_mode $keyword, $file;
73 return "$startmode$content$endmode";
83 my $fh = new IO::File "< $file"
84 or die "Failed to open file \`$file': $!";
86 if ($file !~ /\.(texinfo|texi|txi)$/)
88 print stderr "Passing \`$file' through unprocessed.\n";
89 # Just cat any file that doesn't look like a Texinfo source.
90 while (my $line = $fh->getline)
97 print stderr "Processing \`$file'.\n";
105 my $last_header = "";
108 my $table_header = "";
109 my $table_footer = "";
111 while ($_ = $fh->getline)
113 if (!$gotone && /^\@c ----- START MAN $texi_num -----$/)
119 # Skip ahead until our man section.
122 # If we find the end tag we are done.
123 last if /^\@c ----- END MAN $texi_num -----$/;
125 # Need to do this everywhere. i.e., before we print example
126 # lines, since literal back slashes can appear there too.
132 s/(?<!-)---(?!-)/\\(em/g;
133 s/\@bullet({}|\b)/\\(bu/g;
134 s/\@dots({}|\b)/\\&.../g;
136 # Examples should be indented and otherwise untouched
140 print qq{.SP\n.PD 0\n};
146 if (/^\@end example$/)
149 print qq{\n.PD\n.IP "" $indent\n};
159 # Preserve the newline.
160 $_ = qq{.IP "" $indent\n} . $_;
163 # Compress blank lines into a single line. This and its
164 # corresponding skip purposely bracket the @menu and comment
165 # removal so that blanks on either side of a menu are
166 # compressed after the menu is removed.
174 if (/^\@(ignore|menu)$/)
179 # Delete menu contents.
182 next unless /^\@end (ignore|menu)$/;
188 next if /^\@c(omment)?\b/;
191 next if /^\@include\b/;
193 # It's okay to ignore this keyword - we're not using any
194 # first-line indent commands at all.
195 next if s/^\@noindent\s*$//;
197 # @need is only significant in printed manuals.
198 next if s/^\@need\s+.*$//;
200 # If we didn't hit the previous check and $inblank is set, then
201 # we just finished with some number of blanks. Print the man
202 # page blank symbol before continuing processing of this line.
210 $last_header = $1 if s/^\@node\s+(.*)$/.SH "$1"/;
211 if (/^\@appendix\w*\s+(.*)$/)
214 $content =~ s/^$last_header(\\\(em|\s+)?//;
215 next if $content =~ /^\s*$/;
216 s/^\@appendix\w*\s+.*$/.SS "$content"/;
219 # Tables are similar to examples, except we need to handle the
221 if (/^\@(itemize|table)(\s+(.*))?$/)
224 push @table_headers, $table_header;
225 push @table_footers, $table_footer;
229 my $bullet = $content;
230 $table_header = qq{.IP "$bullet" $indent\n};
235 my $hi = $indent - 2;
236 $table_header = qq{.IP "" $hi\n};
237 $table_footer = qq{\n.IP "" $indent};
240 $table_header .= "$content\{";
241 $table_footer = "\}$table_footer";
250 if (/^\@end (itemize|table)$/)
252 $table_header = pop @table_headers;
253 $table_footer = pop @table_footers;
258 s/^\@itemx?(\s+(.*))?$/$table_header$2$table_footer/;
259 # Fall through so the rest of the table lines are
260 # processed normally.
264 s/^\@cindex\s+(.*)$/.IX "$1"/;
266 $_ = "$last$_" if $last;
272 (?{ push @parent, $1 }) # Keep track of the last keyword
273 # keyword we encountered.
275 (?> (?:[^{}]|(?<=\@)[{}])*) # Non-braces without backtracking
277 (??{ $nk }) # Nested keywords
280 (?{ pop (@parent) }) # Lose track of the current keyword.
284 while (s/$nk/do_keyword $file, $parent[$#parent], $1, $2/e)
286 # Do nothing except replace our last-replacement
287 # tracker - the replacement regex above is handling
291 s/$nk/do_keyword $file, $parent[$#parent], $1, $2/ge;
295 # If there is still an opening keyword left, we need to
296 # find the close bracket. Set $last to append the next
297 # line in the next pass.
302 # Finally, unprotect texinfo special characters.
306 # Verify we haven't left commands unprocessed.
307 die "Unprocessed command at line $. of file \`$file': "
308 . ($1 ? "$1\n" : "<EOL>\n")
309 if /^(?>(?:[^\@]|\@\@)*)\@(\w+|.|$)/;
314 # And print whatever's left.