123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822 |
- # Texinfo.pm: format Pod as Texinfo.
- #
- # Copyright 2011, 2012, 2013, 2014 Free Software Foundation, Inc.
- #
- # This program is free software; you can redistribute it and/or modify
- # it under the terms of the GNU General Public License as published by
- # the Free Software Foundation; either version 3 of the License,
- # or (at your option) any later version.
- #
- # This program is distributed in the hope that it will be useful,
- # but WITHOUT ANY WARRANTY; without even the implied warranty of
- # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- # GNU General Public License for more details.
- #
- # You should have received a copy of the GNU General Public License
- # along with this program. If not, see <http://www.gnu.org/licenses/>.
- #
- # Original author: Patrice Dumas <pertusus@free.fr>
- # Parts from L<Pod::Simple::HTML>.
- package Pod::Simple::Texinfo;
- require 5;
- use strict;
- use Carp qw(cluck);
- #use Pod::Simple::Debug (3);
- use Pod::Simple::PullParser ();
- use Texinfo::Convert::NodeNameNormalization qw(normalize_node);
- use Texinfo::Parser qw(parse_texi_line parse_texi_text);
- use Texinfo::Convert::Texinfo;
- use Texinfo::Convert::TextContent;
- use Texinfo::Common qw(protect_comma_in_tree protect_first_parenthesis
- protect_hashchar_at_line_beginning);
- use Texinfo::Transformations;
- use vars qw(
- @ISA $VERSION
- );
- @ISA = ('Pod::Simple::PullParser');
- $VERSION = '0.01';
- #use UNIVERSAL ();
- # Allows being called from the comand line as
- # perl -w -MPod::Simple::Texinfo -e Pod::Simple::Texinfo::go thingy.pod
- sub go { Pod::Simple::Texinfo->parse_from_file(@ARGV); exit 0 }
- my %head_commands_level;
- foreach my $level (1 .. 4) {
- $head_commands_level{'head'.$level} = $level;
- }
- my @numbered_sectioning_commands = ('part', 'chapter', 'section', 'subsection',
- 'subsubsection');
- my @appendix_sectioning_commands = ('part', 'appendix', 'appendixsec',
- 'appendixsubsec', 'appendixsubsubsec');
- my @unnumbered_sectioning_commands = ('part', 'unnumbered', 'unnumberedsec',
- 'unnumberedsubsec', 'unnumberedsubsubsec');
- my @raw_formats = ('html', 'HTML', 'docbook', 'DocBook', 'texinfo',
- 'Texinfo');
- # from other Pod::Simple modules. Creates accessor subroutine.
- __PACKAGE__->_accessorize(
- 'texinfo_sectioning_base_level',
- 'texinfo_short_title',
- 'texinfo_man_url_prefix',
- 'texinfo_sectioning_style',
- 'texinfo_add_upper_sectioning_command',
- 'texinfo_section_nodes',
- 'texinfo_internal_pod_manuals',
- );
- my $sectioning_style = 'numbered';
- #my $sectioning_base_level = 2;
- my $sectioning_base_level = 0;
- my $man_url_prefix = 'http://man.he.net/man';
- sub new
- {
- my $class = shift;
- my $new = $class->SUPER::new(@_);
- $new->accept_targets(@raw_formats);
- $new->preserve_whitespace(1);
- $new->texinfo_section_nodes(0);
- $new->texinfo_sectioning_base_level ($sectioning_base_level);
- $new->texinfo_man_url_prefix ($man_url_prefix);
- $new->texinfo_sectioning_style ($sectioning_style);
- $new->texinfo_add_upper_sectioning_command(1);
- return $new;
- }
- sub run
- {
- my $self = shift;
- # In case the caller changed the formats
- my @formats = $self->accept_targets();
- foreach my $format (@formats) {
- if (lc($format) eq 'texinfo') {
- $self->{'texinfo_raw_format_commands'}->{$format} = '';
- $self->{'texinfo_if_format_commands'}->{':'.$format} = '';
- } else {
- $self->{'texinfo_raw_format_commands'}->{$format} = lc($format);
- $self->{'texinfo_if_format_commands'}->{':'.$format} = lc($format);
- }
- }
- my $base_level = $self->texinfo_sectioning_base_level;
- $base_level = 1 if ($base_level <= 1);
- if ($self->texinfo_sectioning_style eq 'numbered') {
- $self->{'texinfo_sectioning_commands'} = \@numbered_sectioning_commands;
- } elsif ($self->texinfo_sectioning_style eq 'unnumbered') {
- $self->{'texinfo_sectioning_commands'} = \@unnumbered_sectioning_commands;
- } else {
- $self->{'texinfo_sectioning_commands'} = \@appendix_sectioning_commands;
- }
- foreach my $heading_command (keys(%head_commands_level)) {
- my $level = $head_commands_level{$heading_command} + $base_level -1;
- if (!defined($self->{'texinfo_sectioning_commands'}->[$level])) {
- $self->{'texinfo_head_commands'}->{$heading_command}
- = $self->{'texinfo_sectioning_commands'}->[-1];
- } else {
- $self->{'texinfo_head_commands'}->{$heading_command}
- = $self->{'texinfo_sectioning_commands'}->[$level];
- }
- }
- $self->{'texinfo_internal_pod_manuals_hash'} = {};
- my $manuals = $self->texinfo_internal_pod_manuals();
- if ($manuals) {
- foreach my $manual (@$manuals) {
- $self->{'texinfo_internal_pod_manuals_hash'}->{$manual} = 1;
- }
- }
- if ($self->bare_output()) {
- $self->_convert_pod();
- } else {
- $self->_preamble();
- $self->_convert_pod();
- $self->_postamble();
- }
- }
- my $STDIN_DOCU_NAME = 'stdin';
- sub _preamble($)
- {
- my $self = shift;
- my $fh = $self->{'output_fh'};
- if (!defined($self->texinfo_short_title)) {
- my $short_title = $self->get_short_title();
- if (defined($short_title) and $short_title =~ m/\S/) {
- $self->texinfo_short_title($short_title);
- }
- }
- if ($self->texinfo_sectioning_base_level == 0) {
- #print STDERR "$fh\n";
- print $fh '\input texinfo'."\n";
- my $setfilename;
- if (defined($self->texinfo_short_title)) {
- $setfilename = _pod_title_to_file_name($self->texinfo_short_title);
- } else {
- # FIXME maybe output filename would be better than source_filename?
- my $source_filename = $self->source_filename();
- if (defined($source_filename) and $source_filename ne '') {
- if ($source_filename eq '-') {
- $setfilename = $STDIN_DOCU_NAME;
- } else {
- $setfilename = $source_filename;
- $setfilename =~ s/\.(pod|pm)$//i;
- }
- }
- }
- if (defined($setfilename) and $setfilename =~ m/\S/) {
- $setfilename = _protect_text($setfilename, 1);
- $setfilename .= '.info';
- print $fh "\@setfilename $setfilename\n\n"
- }
- # FIXME depend on =encoding
- print $fh '@documentencoding utf-8'."\n\n";
- my $title = $self->get_title();
- if (defined($title) and $title =~ m/\S/) {
- print $fh "\@settitle "._protect_text($title, 1)."\n\n";
- }
- print $fh "\@node Top\n";
- if (defined($self->texinfo_short_title)) {
- print $fh "\@top "._protect_text($self->texinfo_short_title, 1)."\n\n";
- }
- } elsif (defined($self->texinfo_short_title)
- and $self->texinfo_add_upper_sectioning_command) {
- my $level = $self->texinfo_sectioning_base_level() - 1;
- my $name = _protect_text($self->texinfo_short_title, 1);
- my $node_name = _prepare_anchor($self, $name);
- my $anchor = '';
- my $node = '';
- if ($node_name =~ /\S/) {
- if (!$self->texinfo_section_nodes
- or $self->{'texinfo_sectioning_commands'}->[$level] eq 'part') {
- $anchor = "\@anchor{$node_name}\n";
- } else {
- $node = "\@node $node_name\n";
- }
- }
- print $fh "$node\@$self->{'texinfo_sectioning_commands'}->[$level] "
- ._protect_text($self->texinfo_short_title, 1)."\n$anchor\n";
- }
- }
- # 'out' is out of the context, for now for index entries.
- sub _output($$$;$)
- {
- my $fh = shift;
- my $accumulated_stack = shift;
- my $text = shift;
- my $out = shift;
- if (scalar(@$accumulated_stack)) {
- if ($out) {
- $accumulated_stack->[-1]->{'out'} .= $text;
- } else {
- $accumulated_stack->[-1]->{'text'} .= $text;
- }
- } else {
- print $fh $text;
- }
- }
- sub _begin_context($$)
- {
- my $accumulated_stack = shift;
- my $tag = shift;
- push @$accumulated_stack, {'text' => '', 'tag' => $tag,
- 'out' => ''};
- }
- sub _end_context($)
- {
- my $accumulated_stack = shift;
- my $previous_context = pop @$accumulated_stack;
- return ($previous_context->{'text'}, $previous_context->{'out'});
- }
- sub _protect_text($;$)
- {
- my $text = shift;
- my $remove_new_lines = shift;
- cluck if (!defined($text));
- $text =~ s/\n/ /g if ($remove_new_lines);
- $text =~ s/([\@\{\}])/\@$1/g;
- return $text;
- }
- sub _pod_title_to_file_name($)
- {
- my $name = shift;
- $name =~ s/\s+/_/g;
- $name =~ s/::/-/g;
- $name =~ s/[^\w\.-]//g;
- $name = '_' if ($name eq '');
- return $name;
- }
- sub _protect_comma($)
- {
- my $texinfo = shift;
- my $tree = parse_texi_line(undef, $texinfo);
- $tree = protect_comma_in_tree($tree);
- return Texinfo::Convert::Texinfo::convert($tree);
- }
- sub _protect_hashchar($)
- {
- my $texinfo = shift;
- # protect # first in line
- if ($texinfo =~ /#/) {
- my $tree = parse_texi_text(undef, $texinfo);
- protect_hashchar_at_line_beginning(undef, $tree);
- return Texinfo::Convert::Texinfo::convert($tree);
- } else {
- return $texinfo;
- }
- }
- sub _reference_to_text_in_texi($)
- {
- my $texinfo = shift;
- my $tree = parse_texi_text(undef, $texinfo);
- Texinfo::Transformations::reference_to_arg_in_tree(undef, $tree);
- return Texinfo::Convert::Texinfo::convert($tree);
- }
- sub _section_manual_to_node_name($$$)
- {
- my $self = shift;
- my $manual = shift;
- my $section = shift;
- my $base_level = shift;
- if (defined($manual) and $base_level > 0) {
- return _protect_text($manual, 1). " $section";
- } else {
- return $section;
- }
- }
- sub _normalize_texinfo_name($$)
- {
- # Pod may be more forgiven than Texinfo, so we go through
- # a normalization, by parsing and converting back to Texinfo
- my $name = shift;
- my $command = shift;
- my $texinfo_text;
- if ($command eq 'anchor') {
- $texinfo_text = "\@anchor{$name}";
- } else {
- # item is not correct since it cannot happen outside of a table
- # context, so we use @center which accepts the same on the line
- if ($command eq 'item') {
- $command = 'center';
- }
- $texinfo_text = "\@$command $name\n";
- }
- my $tree = parse_texi_text(undef, $texinfo_text);
- if ($command eq 'anchor') {
- #print STDERR "GGG $tree->{'contents'}->[0]->{'cmdname'}\n";
- $tree->{'contents'}->[0]->{'args'}->[-0]->{'contents'}
- = protect_first_parenthesis($tree->{'contents'}->[0]->{'args'}->[-0]->{'contents'});
- }
- my $fixed_text = Texinfo::Convert::Texinfo::convert($tree, 1);
- my $result = $fixed_text;
- if ($command eq 'anchor') {
- $result =~ s/^\@anchor\{(.*)\}$/$1/s;
- } else {
- chomp($result);
- $result =~ s/^\@$command (.*)$/$1/s;
- }
- return $result;
- }
- sub _node_name($$)
- {
- my $self = shift;
- my $texinfo_node_name = shift;
- chomp $texinfo_node_name;
- $texinfo_node_name
- = $self->_section_manual_to_node_name($self->texinfo_short_title,
- $texinfo_node_name,
- $self->texinfo_sectioning_base_level);
- # also change refs to text
- return _reference_to_text_in_texi($texinfo_node_name);
- }
- sub _prepare_anchor($$)
- {
- my $self = shift;
- my $texinfo_node_name = shift;
- my $node = _normalize_texinfo_name($texinfo_node_name, 'anchor');
- if ($node !~ /\S/) {
- return '';
- }
- # Now we know that we have something.
- my $node_tree = parse_texi_line(undef, $node);
- my $normalized_base = normalize_node($node_tree);
- my $normalized = $normalized_base;
- my $number_appended = 0;
- while ($self->{'texinfo_nodes'}->{$normalized}) {
- $number_appended++;
- $normalized = "${normalized_base}-$number_appended";
- }
- my $node_name;
- if ($number_appended) {
- $texinfo_node_name = "$node $number_appended";
- $node_tree = parse_texi_line(undef, $texinfo_node_name);
- }
- $node_tree = protect_comma_in_tree($node_tree);
- $self->{'texinfo_nodes'}->{$normalized} = $node_tree;
- my $final_node_name = Texinfo::Convert::Texinfo::convert($node_tree, 1);
- return $final_node_name;
- }
- # from Pod::Simple::HTML general_url_escape
- sub _url_escape($)
- {
- my $string = shift;
- $string =~ s/([^\x00-\xFF])/join '', map sprintf('%%%02X',$_), unpack 'C*', $1/eg;
- # express Unicode things as urlencode(utf(orig)).
- # A pretty conservative escaping, behoovey even for query components
- # of a URL (see RFC 2396)
- $string =~ s/([^-_\.!~*()abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789])/sprintf('%%%02X',ord($1))/eg;
- # Yes, stipulate the list without a range, so that this can work right on
- # all charsets that this module happens to run under.
- # Altho, hmm, what about that ord? Presumably that won't work right
- # under non-ASCII charsets. Something should be done
- # about that, I guess?
- return $string;
- }
- my %tag_commands = (
- 'F' => 'file',
- 'S' => 'w',
- 'I' => 'emph',
- 'B' => 'strong', # or @b?
- 'C' => 'code'
- );
- my %environment_commands = (
- 'Verbatim' => 'verbatim',
- 'over-text' => 'table @asis',
- 'over-bullet' => 'itemize',
- 'over-number' => 'enumerate',
- 'over-block' => 'quotation',
- );
- my %line_commands = (
- 'item-bullet' => 'item',
- 'item-text' => 'item',
- 'item-number' => 'item',
- 'encoding' => 'documentencoding'
- );
- foreach my $tag (keys(%head_commands_level)) {
- $line_commands{$tag} = 1;
- }
- my %tags_index_before;
- my %context_tags;
- foreach my $context_tag (keys(%line_commands), 'L', 'X', 'Para') {
- $context_tags{$context_tag} = 1;
- }
- # do not appear as parsed token
- # E entity/character
- sub _convert_pod($)
- {
- my $self = shift;
- my $fh = $self->{'output_fh'};
- my ($token, $type, $tagname, $top_seen);
- my @accumulated_output;
- my @format_stack;
- while($token = $self->get_token()) {
- my $type = $token->type();
- #print STDERR "* type $type\n";
- #print STDERR $token->dump()."\n";
- if ($type eq 'start') {
- my $tagname = $token->tagname();
- if ($context_tags{$tagname}) {
- if ($tagname eq 'L') {
- my $linktype = $token->attr('type');
- my $content_implicit = $token->attr('content-implicit');
- #print STDERR " L: $linktype\n";
- #my @attrs = keys %{$token->attr_hash};
- #print STDERR " @attrs\n";
- #my $raw_L = $token->attr('raw').'';
- #print STDERR " $token->attr('raw'): $raw_L\n";
- my ($url_arg, $texinfo_node, $texinfo_manual, $texinfo_section);
- if ($linktype eq 'man') {
- # NOTE: the .'' is here to force the $token->attr to ba a real
- # string and not an object.
- # NOTE 2: It is not clear that setting the url should be done
- # here, maybe this should be in the Texinfo HTML converter.
- # However, there is a 'man' category here and not in Texinfo,
- # so the information is more precise in pod.
- my $replacement_arg = $token->attr('to').'';
- # regexp from Pod::Simple::HTML resolve_man_page_link
- # since it is very small, it is likely that copyright cannot be
- # claimed for that part.
- $replacement_arg =~ /^([^(]+)(?:[(](\d+)[)])?$/;
- my $page = $1;
- my $section = $2;
- if (defined($page) and $page ne '') {
- $section = 1 if (!defined($section));
- # it is unlikely that there is a comma because of _url_escape
- # but to be sure there is still a call to _protect_comma.
- $url_arg
- = _protect_comma(_protect_text(
- $self->texinfo_man_url_prefix
- ."$section/"._url_escape($page)));
- } else {
- $url_arg = '';
- }
- $replacement_arg = _protect_text($replacement_arg);
- _output($fh, \@accumulated_output, "\@url{$url_arg,, $replacement_arg}");
- } elsif ($linktype eq 'url') {
- # NOTE: the .'' is here to force the $token->attr to be a real
- # string and not an object.
- $url_arg = _protect_comma(_protect_text($token->attr('to').''));
- } elsif ($linktype eq 'pod') {
- my $manual = $token->attr('to');
- my $section = $token->attr('section');
- $manual .= '' if (defined($manual));
- $section .= '' if (defined($section));
- if (0) {
- my $section_text = 'UNDEF';
- if (defined($section)) {
- $section_text = $section;
- }
- my $manual_text = 'UNDEF';
- if (defined($manual)) {
- $manual_text = $manual;
- }
- print STDERR "L: $linktype $manual_text/$section_text\n";
- }
- if (defined($manual)) {
- if (! defined($section) or $section !~ m/\S/) {
- if ($self->{'texinfo_internal_pod_manuals_hash'}->{$manual}) {
- $section = 'NAME';
- }
- }
- if ($self->{'texinfo_internal_pod_manuals_hash'}->{$manual}) {
- $texinfo_node =
- $self->_section_manual_to_node_name($manual, $section,
- $self->texinfo_sectioning_base_level);
- } else {
- $texinfo_manual = _protect_text(_pod_title_to_file_name($manual));
- if (defined($section)) {
- $texinfo_node = $section;
- } else {
- $texinfo_node = '';
- }
- }
- } elsif (defined($section) and $section =~ m/\S/) {
- $texinfo_node =
- $self->_section_manual_to_node_name(
- $self->texinfo_short_title, $section,
- $self->texinfo_sectioning_base_level);
- $texinfo_section = _normalize_texinfo_name(
- _protect_comma(_protect_text($section)), 'section');
- #print STDERR "L: internal: $texinfo_node/$texinfo_section\n";
- }
- $texinfo_node = _normalize_texinfo_name(
- _protect_comma(_protect_text($texinfo_node)), 'anchor');
- #print STDERR "L: normalized node: $texinfo_node\n";
- # for pod, 'to' is the pod manual name. Then 'section' is the
- # section.
- }
- push @format_stack, [$linktype, $content_implicit, $url_arg,
- $texinfo_manual, $texinfo_node, $texinfo_section];
- #if (defined($to)) {
- # print STDERR " | $to\n";
- #} else {
- # print STDERR "\n";
- #}
- #print STDERR $token->dump."\n";
- }
- _begin_context(\@accumulated_output, $tagname);
- } elsif ($tag_commands{$tagname}) {
- _output($fh, \@accumulated_output, "\@$tag_commands{$tagname}\{");
- } elsif ($environment_commands{$tagname}) {
- _output($fh, \@accumulated_output, "\@$environment_commands{$tagname}\n");
- if ($tagname eq 'Verbatim') {
- push @format_stack, 'verbatim';
- }
- } elsif ($tagname eq 'for') {
- my $target = $token->attr('target');
- push @format_stack, $target;
- if ($self->{'texinfo_raw_format_commands'}->{$target}) {
- _output($fh, \@accumulated_output,
- "\@$self->{'texinfo_raw_format_commands'}->{$target}\n");
- } elsif ($self->{'texinfo_if_format_commands'}->{$target}) {
- _output($fh, \@accumulated_output,
- "\@if$self->{'texinfo_if_format_commands'}->{$target}\n");
- }
- }
- } elsif ($type eq 'text') {
- my $text;
- if (@format_stack and !ref($format_stack[-1])
- and ((defined($self->{'texinfo_raw_format_commands'}->{$format_stack[-1]})
- and !$self->{'texinfo_raw_format_commands'}->{$format_stack[-1]})
- or ($format_stack[-1] eq 'verbatim'))) {
- $text = $token->text();
- } else {
- $text = _protect_text($token->text());
- if (@format_stack and !ref($format_stack[-1])
- and ($self->{'texinfo_raw_format_commands'}->{$format_stack[-1]})) {
- $text =~ s/^(\s*)#(\s*(line)? (\d+)(( "([^"]+)")(\s+\d+)*)?\s*)$/$1\@hashchar{}$2/mg;
- }
- }
- _output($fh, \@accumulated_output, $text);
- } elsif ($type eq 'end') {
- my $tagname = $token->tagname();
- if ($context_tags{$tagname}) {
- my ($result, $out) = _end_context(\@accumulated_output);
- #print STDERR "end: $tagname: $result, $out\n";
- my $texinfo_node = '';
- if ($line_commands{$tagname}) {
- my ($command, $command_argument);
- if ($head_commands_level{$tagname}) {
- $command = $self->{'texinfo_head_commands'}->{$tagname};
- } elsif ($line_commands{$tagname}) {
- $command = $line_commands{$tagname};
- }
- if ($head_commands_level{$tagname} or $tagname eq 'item-text') {
- chomp ($result);
- $result =~ s/\n/ /g;
- $result =~ s/^\s*//;
- $result =~ s/\s*$//;
- $command_argument = _normalize_texinfo_name($result, $command);
- if ($result =~ /\S/ and $command_argument !~ /\S/) {
- # use some raw text if the expansion lead to an empty section
- my $tree = parse_texi_line(undef, $result);
- my $converter = Texinfo::Convert::TextContent->converter();
- $command_argument = _protect_text($converter->convert_tree($tree));
- }
- my $anchor = '';
- my $node_name = _prepare_anchor($self, _node_name($self, $result));
- if ($node_name =~ /\S/) {
- if ($tagname eq 'item-text' or !$self->texinfo_section_nodes) {
- $anchor = "\n\@anchor{$node_name}";
- } else {
- $texinfo_node = "\@node $node_name\n";
- }
- }
- $command_argument .= $anchor;
- } else {
- $command_argument = $result;
- }
- _output($fh, \@accumulated_output,
- "$texinfo_node\@$command $command_argument\n$out\n");
- } elsif ($tagname eq 'Para') {
- _output($fh, \@accumulated_output, $out.
- _protect_hashchar($result)."\n\n");
- } elsif ($tagname eq 'L') {
- my $format = pop @format_stack;
- my ($linktype, $content_implicit, $url_arg,
- $texinfo_manual, $texinfo_node, $texinfo_section) = @$format;
- if ($linktype ne 'man') {
- my $explanation;
- if (defined($result) and $result =~ m/\S/ and !$content_implicit) {
- $explanation = ' '. _protect_comma($result);
- }
- if ($linktype eq 'url') {
- if (defined($explanation)) {
- _output($fh, \@accumulated_output,
- "\@url{$url_arg,$explanation}");
- } else {
- _output($fh, \@accumulated_output,
- "\@url{$url_arg}");
- }
- } elsif ($linktype eq 'pod') {
- if (defined($texinfo_manual)) {
- $explanation = '' if (!defined($explanation));
- _output($fh, \@accumulated_output,
- "\@ref{$texinfo_node,$explanation,, $texinfo_manual}");
- } elsif (defined($explanation)) {
- _output($fh, \@accumulated_output,
- "\@ref{$texinfo_node,$explanation,$explanation}");
- } else {
- if (defined($texinfo_section)
- and $texinfo_section ne $texinfo_node) {
- _output($fh, \@accumulated_output,
- "\@ref{$texinfo_node,, $texinfo_section}");
- } else {
- _output($fh, \@accumulated_output,
- "\@ref{$texinfo_node}");
- }
- }
- }
- }
- } elsif ($tagname eq 'X') {
- my $next_token = $self->get_token();
- if ($next_token) {
- if ($next_token->type() eq 'text') {
- my $next_text = $next_token->text;
- $next_text =~ s/^\s*//;
- $next_token->text($next_text);
- #_output($fh, \@accumulated_output, "\n");
- }
- $self->unget_token($next_token);
- }
- chomp ($result);
- $result =~ s/\n/ /g;
- $result .= "\n";
- _output($fh, \@accumulated_output, "\@cindex $result", 1);
- }
- } elsif ($tag_commands{$tagname}) {
- _output($fh, \@accumulated_output, "}");
- } elsif ($environment_commands{$tagname}) {
- if ($tagname eq 'Verbatim') {
- pop @format_stack;
- _output($fh, \@accumulated_output, "\n");
- }
- my $tag = $environment_commands{$tagname};
- $tag =~ s/ .*//;
- _output($fh, \@accumulated_output, "\@end $tag\n\n");
- } elsif ($tagname eq 'for') {
- my $target = pop @format_stack;
- if ($self->{'texinfo_raw_format_commands'}->{$target}) {
- _output($fh, \@accumulated_output,
- "\n\@end $self->{'texinfo_raw_format_commands'}->{$target}\n");
- } elsif ($self->{'texinfo_if_format_commands'}->{$target}) {
- _output($fh, \@accumulated_output,
- "\@end if$self->{'texinfo_if_format_commands'}->{$target}\n");
- }
- }
- }
- }
- }
- sub _postamble($)
- {
- my $self = shift;
- my $fh = $self->{'output_fh'};
- if ($self->texinfo_sectioning_base_level == 0) {
- #print STDERR "$fh\n";
- print $fh "\@bye\n";
- }
- }
- 1;
- __END__
- =head1 NAME
- Pod::Simple::Texinfo - format Pod as Texinfo
- =head1 SYNOPSIS
- # From the command like
- perl -MPod::Simple::Texinfo -e Pod::Simple::Texinfo::go thingy.pod
- # From perl
- my $new = Pod::Simple::Texinfo->new;
- $new->texinfo_sectioning_style('unnumbered');
- my $from = shift @ARGV;
- my $to = $from;
- $to =~ s/\.(pod|pm)$/.texi/i;
- $new->parse_from_file($from, $to);
- =head1 DESCRIPTION
- This class is for making a Texinfo rendering of a Pod document.
- This is a subclass of L<Pod::Simple::PullParser> and inherits all its
- methods (and options).
- It supports producing a standalone manual per Pod (the default) or
- render the Pod as a chapter, see L</texinfo_sectioning_base_level>.
- =head1 METHODS
- =over
- =item texinfo_sectioning_base_level
- Sets the level of the head1 commands. 1 is for the @chapter/@unnumbered
- level. If set to 0, the head1 commands level is still 1, but the output
- manual is considered to be a standalone manual. If not 0, the pod file is
- rendered as a fragment of a Texinfo manual.
- =item texinfo_man_url_prefix
- String used as a prefix for man page urls. Default
- is C<http://man.he.net/man>.
- =item texinfo_sectioning_style
- Default is C<numbered>, using the numbered sectioning Texinfo @-commands
- (@chapter, @section...). Giving C<unnumbered> leads to using unnumbered
- sectioning command variants (@unnumbered...), and any other value would
- lead to using appendix sectioning command variants (@appendix...).
- =item texinfo_add_upper_sectioning_command
- If set (the default case), a sectioning command is added at the beginning
- of the output for the whole document, using the module name, at the level
- above the level set by L<texinfo_sectioning_base_level>. So there will be
- a C<@part> if the level is equal to 1, a C<@chapter> if the level is equal
- to 2 and so on and so forth. If the base level is 0, a C<@top> command is
- output instead.
- =item texinfo_section_nodes
- If set, add C<@node> and not C<@anchor> for each sectioning command.
- =back
- =head1 SEE ALSO
- L<Pod::Simple>. L<Pod::Simple::PullParser>. The Texinfo manual.
- =head1 COPYRIGHT
- Copyright (C) 2011, 2012 Free Software Foundation, Inc.
- This library is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 3 of the License,
- or (at your option) any later version.
- C<_url_escape> is C<general_url_escape> from L<Pod::Simple::HTML>.
- =head1 AUTHOR
- Patrice Dumas E<lt>pertusus@free.frE<gt>. Parts from L<Pod::Simple::HTML>.
- =cut
|