#!/usr/bin/perl # TODO: texinfo fails on @cinde xin title elements etc. *sigh* use Pod::POM; sub escape_texi($) { local $_ = shift; s/([\@\{\}])/\@$1/g; s/\n+/ /g; $_; } sub example { my $text = $_[0]; $text =~ s/\n+$//; $text =~ s/([\@\{\}])/\@$1/g; "\n\n\@example\n" . $text . "\n\@end example\n\n"; } my @nodes; # nodelist my @ctx; # curstack sub out { $ctx[-1]{out} .= join "", @_; } sub TEX::view_seq_code { "\@t{$_[1]}" } sub TEX::view_seq_bold { "\@strong{$_[1]}" } sub TEX::view_seq_italic { "\@emph{$_[1]}" } sub TEX::view_seq_space { escape_texi $_[1] } sub TEX::view_seq_text { escape_texi $_[1] } sub TEX::view_seq_link { $_[1] } sub TEX::view_seq_index { "\n\@cindex $_[1]\n$_[1]" } *TXT::view_seq_code = *TXT::view_seq_bold = *TXT::view_seq_italic = *TXT::view_seq_space = *TXT::view_seq_text = *TXT::view_seq_link = *TXT::view_seq_index = sub { $_[1] }; my %ignore = ( "SEE ALSO" => 1, "AUTHOR" => 1, ); sub parse_pod { my ($data) = @_; local $out; local $Pod::POM::DEFAULT_VIEW = TEX::; my $parser = new Pod::POM; my $pod = $parser->parse_text ($data) or die; my $walker; $walker = sub { my $n = $_[0]; my $t = $n->type; if ($t eq "text") { out $n->text . "\n\@refill\n"; } elsif ($t eq "pod") { $walker->($_) for $n->content; } elsif ($t eq "verbatim") { out example $n->text; } elsif ($t eq "head1") { return if $ignore{$n->title}; out "\n\@section " . $n->title . "\n"; $walker->($_) for $n->content; out "\n"; } elsif ($t eq "head2") { out "\n\n\@subsection " . $n->title . "\n"; $walker->($_) for $n->content; } elsif ($t eq "over") { out "\n\n\@itemize\n"; $walker->($_) for $n->content; out "\@end itemize\n\n"; } elsif ($t eq "item") { out "\n\n\@item\n\@b{" . $n->title . "}\n\n"; if ($n->title->present (TXT::) =~ /^\s*([a-zA-Z0-9\-\_]+)\s*=/) { out "\@cindex $1\n"; } $walker->($_) for $n->content; } elsif ($t eq "begin") { local $Pod::POM::DEFAULT_VIEW = Pod::POM::View::Pod; my $format = $n->format; if ($format =~ /texinfo\s+header/) { $header = $n->content; } elsif ($format =~ /texinfo\s+footer/) { $footer = $n->content; } else { out $n->content; } } elsif ($t eq "for") { my $text = $n->text; if ($text =~ /^menu-begin/) { out "\n\@menu\n"; push @ctx, {}; # dummy node } elsif ($text =~ /^menu-item (.*?)::\s+(.*)/) { my ($name, $desc) = ($1, $2); push @{ $ctx[-2]{menu} }, [$name, $desc]; $ctx[-2]{width} = length $name if $ctx[-2]{width} < length $name; my $ctx = { name => $name, up => $ctx[-2]{name}, }; push @nodes, $ctx; $ctx[-1] = $ctx; } elsif ($text =~ /^menu-end/) { pop @ctx; for (@{ $ctx[-1]{menu} }) { out sprintf "* %-*s %s\n", $ctx[-1]{width} + 2, "$_->[0]::", $_->[1]; } out "\@end menu\n"; } elsif ($text =~ /^include (\S+) (.*)/) { my ($type, $path) = ($1, $2); open my $x, "<$path" or die "$path: $!"; my $data = do { local $/; <$x> }; if ($type eq "pod") { out parse_pod ($data); } elsif ($type eq "text") { out $data; } elsif ($type eq "example") { out example $data; } } else { die "UNKNOWN for command <$text>\n"; } } else { die "UNKNOWN NODE $t\n"; } }; $walker->($pod); } @ctx = @nodes = { up => "(dir)", name => "Top", }; parse_pod do { local $/; <> }; print $header; for (0 .. $#nodes) { my $node = $nodes[$_]; my $prev = $_ > 0 ? $nodes[$_-1] : undef; my $next = $nodes[$_+1]; my $chapter = $node->{name} eq "Top" ? "Introduction" : $node->{name}; print "\@node $node->{name},$next->{name},$prev->{name},$node->{up}\n\n", "\@chapter $chapter\n", "$node->{out}\n\n"; } print $footer;